4.6.0
Freundlich's C++ toolkit
Loading...
Searching...
No Matches
fcppt.record

Description

A record class that holds named elements in a generic way.

Motivation

A set of name-type pairs, for example { age : int, name : string }, is generally called a record. In C++, these are usually declared using classes or structs:

struct person
{
int age;
std::string name;
};

The shortcoming is that such a struct provides no generic structure. Imagine you would like to write a generic function that prints such a struct, given you already know how to print ints and strings. A concrete implementation would look like this:

void print(std::ostream &_stream, person const &_person)
{
_stream << "age: " << _person.age << ", "
<< "name: " << _person.name;
}

This, however, only works for the concrete type person. To find a more abstract representation, we need to specify which elements a struct has in a generic way. To this end, we first of all need to create unique types that represent element names which we call labels. Such a label together with a unique tag type is created by FCPPT_RECORD_MAKE_LABEL:

// age = fcppt::record::label<T> for a unique tag type T
// name = fcppt::record::label<T> for a unique tag type T

A record element is represented by fcppt::record::element. It gets a label together with a type as its template parameters:

Finally, a record object consists of a list of elements:

Before we continue, here is a small example of how to use such a record:

person test_person{age{} = 1, name{} = std::string("test")};
std::cout << fcppt::record::get<age>(test_person) << '\n';
fcppt::record::set<age>(test_person, 2);
std::cout << fcppt::record::get<age>(test_person) << '\n';

The initialization syntax is further explained in Initialization. The functions fcppt::record::get and fcppt::record::set are used to read and write elements.

To return to our goal of creating a generic output function, we first create a function print_label that given a record and a label prints the element for the given label to a stream:

template <typename Label, typename... Elements>
void print_label(std::ostream &_stream, fcppt::record::object<Elements...> const &_record)
{
_stream
// extract the label name
<< ": "
// extract the value for the label
<< fcppt::record::get<Label>(_record) << ", ";
}

The function fcppt::record::element_vector returns an fcppt::mpl::list::object of the elements of a record. Such a list can be used by fcppt::algorithm::loop, which will call a function for every type in the sequence. We use this to call print_label for every element of the record:

template <typename... Elements>
void print(std::ostream &_stream, fcppt::record::object<Elements...> const &_record)
{
// Loop over all types in the record
[&_stream, &_record]<typename L, typename T>(fcppt::tag<fcppt::record::element<L, T>>)
{ print_label<L>(_stream, _record); });
}

Now, if we were to add another member to the person record, say address, we wouldn't have to change our print function.

Initialization

There are two ways to initialize a record: First, we can initialize every element separately. This is done by the special syntax

record{label_1{} = value_1, ..., label_n{} = value_n}

Here, it is important that all labels of the record appear exactly once. Also, the types of the values have to match the types of the record.

person const test_person{
age{} = 42
// error: forgotten name
};
person const test_person{
// error: age specified twice
age{} = 42,
age{} = 10
};
person const test_person{
age{} = 42,
name{} = 10 // error: wrong type for name
};

The second way to initialize a record is via the fcppt::record::init function. It is a generic function that calls a function for every element of the record (from first to last), which can be used to initialize a record in a generic way. Assume that we have the values for our record in a stream:

std::istringstream stream{"42 test"};

We then read the corresponding elements of the record from the stream:

[&stream]<typename L, typename T>(fcppt::record::element<L, T>)
{
T input;
if (!(stream >> input))
{
throw std::runtime_error{"failure"};
}
return input;
})};

The lambda is first called for age_element and second for name_element because of the order they appear in the declaration. So, in the example, age will be 42 and name will be "test".

Labels with an argument

Unlike normal labels, there are also labels that take an additional argument. Consider a sprite that can have a fixed number of textures t_1,...,t_n which will be rendered in order. To create a label that is parameterized, we use FCPPT_RECORD_MAKE_LABEL_ARG:

// Parametrize the texture label with an unsigned int.
// template<unsigned I> using texture = fcppt::record::label<T,I> for a unique tag type T
FCPPT_RECORD_MAKE_LABEL_ARG(texture, unsigned);

Next, we create a type function that takes an unsigned integer I to the I'th texture element:

template <unsigned I>
using sprite_element = fcppt::record::element<texture<I>, std::string>;

Finally, to declare our sprite with N textures, we use a std::integer_sequence to create a record with types sprite_element<0>, ..., sprite_element<N-1>.

template <typename T>
struct sprite_from_ints;
template <unsigned... Ints>
struct sprite_from_ints<std::integer_sequence<unsigned, Ints...>>
{
};
template <unsigned N>
using sprite = typename sprite_from_ints<std::make_integer_sequence<unsigned, N>>::type;

Here is an example that shows how such a sprite can be initialized:

using sprite_type = sprite<2U>;
sprite_type const test_sprite{
texture<0>{} = std::string("ground"), texture<1>{} = std::string("clouds")};

Header files

Header file Description
object_fwd.hpp Contains fcppt::record::object record's declaration.
object_decl.hpp Contains fcppt::record::object record's definition.
object_impl.hpp Contains the definition of fcppt::record::object record's member functions.
object.hpp Includes object_impl.hpp and comparison.hpp.
comparison.hpp Contains operator== and operator!=.
element_fwd.hpp Contains fcppt::record::element element's declaration.
element.hpp Contains fcppt::record::element element's definition.
element_to_label.hpp Contains fcppt::record::element_to_label.
element_to_type.hpp Contains fcppt::record::element_to_type.
from_list_fwd.hpp Contains fcppt::record::from_list.
from_list.hpp Includes fcppt/record/from_list_fwd.hpp and defines fcppt::record::object.
get.hpp Contains fcppt::record::get.
init.hpp Contains fcppt::record::init.
label_fwd.hpp Contains fcppt::record::label label's declaration.
label_decl.hpp Contains fcppt::record::label label's definition.
label_impl.hpp Contains the definition of fcppt::record::label label's member functions.
label.hpp Includes label_impl.hpp.
label_name.hpp Contains fcppt::record::label_name.
label_value_type.hpp Contains fcppt::record::label_value_type.
make_label_fwd.hpp Contains FCPPT_RECORD_MAKE_LABEL and includes label_fwd.hpp.
make_label.hpp Includes make_label_fwd.hpp and label_impl.hpp.
make_label_arg_fwd.hpp Contains FCPPT_RECORD_MAKE_LABEL_ARG and includes label_fwd.hpp.
make_label_arg.hpp Includes make_label_arg_fwd.hpp and label_impl.hpp.
output.hpp Contains operator<< .
set.hpp Contains fcppt::record::set.

Classes

struct  fcppt::record::element< Label, Type >
 An element of a record. More...
 
class  fcppt::record::element_init< Tag, Type >
 The type produced by initializing a single record element. More...
 
struct  fcppt::record::is_element< typename >
 Tests if a type is an fcppt::record::element. More...
 
struct  fcppt::record::is_label< typename >
 Tests if a type is an fcppt::record::label. More...
 
struct  fcppt::record::is_object< T >
 Tests if a type is an fcppt::record::object. More...
 
struct  fcppt::record::label< Tag >
 A type identifying an element of a record. More...
 
class  fcppt::record::object< Elements >
 A generic struct that identifies elements by types. More...
 

Macros

#define FCPPT_RECORD_MAKE_LABEL_ARG(name, arg)
 Creates a parametrized fcppt::record::label.
 
#define FCPPT_RECORD_MAKE_LABEL(name)
 Creates an fcppt::record::label.
 

Typedefs

template<fcppt::mpl::list::object_concept List>
using fcppt::mpl::list::unique = fcppt::mpl::set::to_list<fcppt::mpl::set::from_list_relaxed<List>>
 Removes duplicates from a list.
 
template<fcppt::mpl::list::object_concept Records>
using fcppt::record::all_disjoint
 Tests if multiple records have disjoint label sets.
 
template<typename RecordL , typename RecordR >
using fcppt::record::are_disjoint
 Tests if two records have disjoint label sets.
 
template<typename Record1 , typename Record2 >
using fcppt::record::are_equivalent
 Tests if two records have the same element maps.
 
template<typename RecordL , typename RecordR >
using fcppt::record::disjoint_product = typename fcppt::record::detail::disjoint_product<RecordL, RecordR>::type
 The product of two disjoint records.
 
template<typename Type >
using fcppt::record::element_init_tag = typename fcppt::record::detail::element_init_tag<Type>::type
 The tag type of fcppt::record::element_init.
 
template<typename Type >
using fcppt::record::element_init_type = typename fcppt::record::detail::element_init_type<Type>::type
 The value type of fcppt::record::element_init.
 
template<typename Record >
using fcppt::record::element_map
 A metafunction computing the element map of a record.
 
template<typename Record >
using fcppt::record::element_tag_tuple
 A metafunction returning the elements of record as a fcppt::tuple::object of fcppt::tag types.
 
template<typename Element >
using fcppt::record::element_to_label = typename fcppt::record::detail::element_to_label<Element>::type
 Extracts the type of an fcppt::record::element.
 
template<typename Element >
using fcppt::record::element_to_type
 Extracts the label of an element.
 
template<typename Record >
using fcppt::record::element_vector = typename fcppt::record::detail::element_vector<Record>::type
 A metafunction returning the elements of record as an MPL vector.
 
template<fcppt::mpl::list::object_concept List>
using fcppt::record::from_list = fcppt::mpl::list::as<fcppt::record::object, List>
 Declares a record using an mpl::list.
 
template<typename Record , typename Label >
using fcppt::record::has_label = fcppt::mpl::set::contains<fcppt::record::label_set<Record>, Label>
 Tests if a record has an fcppt::record::label.
 
template<typename... Args>
using fcppt::record::is_vararg_ctor
 Checks if a parameter pack is suitable for record initialization.
 
template<typename Record >
using fcppt::record::label_set
 The set of labels of a record.
 
template<typename Record , typename Label >
using fcppt::record::label_value_type
 Metafunction that computes the value type of a label inside a record.
 
template<typename Record , typename Function >
using fcppt::record::map_elements
 Maps the elements of a vector using a metafunction.
 
template<typename Record , typename Function >
using fcppt::record::map_result
 The result of mapping a record.
 

Functions

template<typename... Types1, typename... Types2>
bool fcppt::record::operator== (fcppt::record::object< Types1... > const &_record1, fcppt::record::object< Types2... > const &_record2)
 Compares two records for equality.
 
template<typename... Types1, typename... Types2>
bool fcppt::record::operator!= (fcppt::record::object< Types1... > const &_record1, fcppt::record::object< Types2... > const &_record2)
 Compares two records for inequality.
 
template<typename Label , typename... Elements>
fcppt::record::label_value_type< fcppt::record::object< Elements... >, Label > const & fcppt::record::get (fcppt::record::object< Elements... > const &_arg)
 Gets an element from a record.
 
template<typename Label , typename... Elements>
fcppt::record::label_value_type< fcppt::record::object< Elements... >, Label > & fcppt::record::get (fcppt::record::object< Elements... > &_arg)
 Gets an element from a record.
 
template<typename Result , typename Function >
Result fcppt::record::init (Function const &_function)
 Initializes a record using a function.
 
template<typename Label >
std::string fcppt::record::label_name ()
 Returns the name of a label as a string.
 
template<typename... Args>
requires ( fcppt::mpl::list::distinct<fcppt::mpl::list::object< fcppt::record::label<fcppt::record::element_init_tag<Args>>...>>::value && fcppt::record::is_vararg_ctor<Args...>::value)
fcppt::record::object< fcppt::record::element< fcppt::record::label< fcppt::record::element_init_tag< Args > >, fcppt::record::element_init_type< Args > >... > fcppt::record::make (Args &&..._args)
 Creates a record from an initializer list.
 
template<typename Record , typename Function >
fcppt::record::map_result< Record, Function > fcppt::record::map (Record &&_record, Function const &_function)
 Maps a record using a function.
 
template<typename Record1 , typename Record2 >
fcppt::record::disjoint_product< std::remove_cvref_t< Record1 >, std::remove_cvref_t< Record2 > > fcppt::record::multiply_disjoint (Record1 &&_record1, Record2 &&_record2)
 Creates the disjoint product of two records.
 
template<typename Ch , typename Traits , typename... Elements>
std::basic_ostream< Ch, Traits > & fcppt::record::operator<< (std::basic_ostream< Ch, Traits > &_stream, fcppt::record::object< Elements... > const &_record)
 Outputs a record to a stream.
 
template<typename Result , typename Arg >
Result fcppt::record::permute (Arg &&_arg)
 Permutes one record into another.
 
template<typename Label , typename... Elements>
void fcppt::record::set (fcppt::record::object< Elements... > &_arg, fcppt::record::label_value_type< fcppt::record::object< Elements... >, Label > const &_value)
 Sets an element in a record by copy.
 
template<typename Label , typename... Elements>
void fcppt::record::set (fcppt::record::object< Elements... > &_arg, fcppt::record::label_value_type< fcppt::record::object< Elements... >, Label > &&_value)
 Sets an element in a record by move.
 

Variables

template<fcppt::mpl::list::object_concept Records>
constexpr bool fcppt::record::all_disjoint_v = fcppt::record::all_disjoint<Records>::value
 Tests if multiple records have disjoint label sets.
 
template<typename RecordL , typename RecordR >
constexpr bool fcppt::record::are_disjoint_v = fcppt::record::are_disjoint<RecordL, RecordR>::value
 Tests if two records have disjoint label sets.
 
template<typename Record1 , typename Record2 >
constexpr bool fcppt::record::are_equivalent_v = fcppt::record::are_equivalent<Record1, Record2>::value
 Tests if two records have the same element maps.
 

Macro Definition Documentation

◆ FCPPT_RECORD_MAKE_LABEL

#define FCPPT_RECORD_MAKE_LABEL ( name)
Value:
FCPPT_RECORD_DETAIL_MAKE_TAG(name); \
\
using name = fcppt::record::label<FCPPT_RECORD_DETAIL_TAG_NAME(name)>

Creates an fcppt::record::label.

Creates an fcppt::record::label, passing it a unique, implementation-defined tag type.

Parameters
nameThe name of the label type.

◆ FCPPT_RECORD_MAKE_LABEL_ARG

#define FCPPT_RECORD_MAKE_LABEL_ARG ( name,
arg )
Value:
template <arg> \
FCPPT_RECORD_DETAIL_MAKE_TAG(name); \
\
template <arg arg_name> \
using name = fcppt::record::label<FCPPT_RECORD_DETAIL_TAG_NAME(name) < arg_name>\
>

Creates a parametrized fcppt::record::label.

Creates an fcppt::record::label, passing it a unique, implementation-defined tag type that depends on a template parameter. The result is a template alias that still takes a parameter of type arg.

Parameters
nameThe name of the label type.
argThe type of the template parameter.

Typedef Documentation

◆ all_disjoint

◆ are_disjoint

template<typename RecordL , typename RecordR >
using fcppt::record::are_disjoint
Initial value:
std::is_same<
fcppt::mpl::set::
intersection<fcppt::record::label_set<RecordL>, fcppt::record::label_set<RecordR>>,

Tests if two records have disjoint label sets.

◆ are_equivalent

template<typename Record1 , typename Record2 >
using fcppt::record::are_equivalent
Initial value:
fcppt::mpl::
map::equal<fcppt::record::element_map<Record1>, fcppt::record::element_map<Record2>>

Tests if two records have the same element maps.

◆ disjoint_product

template<typename RecordL , typename RecordR >
using fcppt::record::disjoint_product = typename fcppt::record::detail::disjoint_product<RecordL, RecordR>::type

The product of two disjoint records.

◆ element_init_tag

template<typename Type >
using fcppt::record::element_init_tag = typename fcppt::record::detail::element_init_tag<Type>::type

The tag type of fcppt::record::element_init.

◆ element_init_type

template<typename Type >
using fcppt::record::element_init_type = typename fcppt::record::detail::element_init_type<Type>::type

The value type of fcppt::record::element_init.

◆ element_map

◆ element_tag_tuple

template<typename Record >
using fcppt::record::element_tag_tuple
Initial value:

A metafunction returning the elements of record as a fcppt::tuple::object of fcppt::tag types.

Template Parameters
RecordMust be an fcppt::record::object.

◆ element_to_label

template<typename Element >
using fcppt::record::element_to_label = typename fcppt::record::detail::element_to_label<Element>::type

Extracts the type of an fcppt::record::element.

Template Parameters
ElementMust be an fcppt::record::element.

◆ element_to_type

template<typename Element >
using fcppt::record::element_to_type
Initial value:
typename fcppt::record::detail::element_to_type<std::remove_cv_t<Element>>::type

Extracts the label of an element.

Template Parameters
ElementMust be an fcppt::record::element.

◆ element_vector

template<typename Record >
using fcppt::record::element_vector = typename fcppt::record::detail::element_vector<Record>::type

A metafunction returning the elements of record as an MPL vector.

Template Parameters
RecordMust be an fcppt::record::object.

◆ from_list

◆ has_label

template<typename Record , typename Label >
using fcppt::record::has_label = fcppt::mpl::set::contains<fcppt::record::label_set<Record>, Label>

Tests if a record has an fcppt::record::label.

◆ is_vararg_ctor

template<typename... Args>
using fcppt::record::is_vararg_ctor
Initial value:
std::conjunction<fcppt::record::detail::is_element_init<std::remove_cvref_t<Args>>...>

Checks if a parameter pack is suitable for record initialization.

◆ label_set

template<typename Record >
using fcppt::record::label_set
Initial value:
fcppt::record::detail::label_list<fcppt::record::element_vector<Record>>>

The set of labels of a record.

Template Parameters
RecordMust be an fcppt::record::object.

◆ label_value_type

template<typename Record , typename Label >
using fcppt::record::label_value_type
Initial value:
fcppt::record::detail::find_element<fcppt::record::element_vector<Record>, Label>>

Metafunction that computes the value type of a label inside a record.

Returns the type the label Label has in Record.

◆ map_elements

template<typename Record , typename Function >
using fcppt::record::map_elements
Initial value:

Maps the elements of a vector using a metafunction.

Template Parameters
RecordMust be an fcppt::record::object.
FunctionA metafunction accepting fcppt::record::element as parameter and returning the new mapped type.

◆ map_result

template<typename Record , typename Function >
using fcppt::record::map_result

◆ unique

Function Documentation

◆ get() [1/2]

template<typename Label , typename... Elements>
fcppt::record::label_value_type< fcppt::record::object< Elements... >, Label > & fcppt::record::get ( fcppt::record::object< Elements... > & _arg)
inline

Gets an element from a record.

Returns the element identified by Label from _arg.

◆ get() [2/2]

template<typename Label , typename... Elements>
fcppt::record::label_value_type< fcppt::record::object< Elements... >, Label > const & fcppt::record::get ( fcppt::record::object< Elements... > const & _arg)
inline

Gets an element from a record.

Returns the element identified by Label from _arg.

◆ init()

template<typename Result , typename Function >
Result fcppt::record::init ( Function const & _function)
inline

Initializes a record using a function.

Let element<L_1,T_1>, ..., element<L_n,T_n> be the elements of Result. _function is then called as (element<L_i,T_i>) for i = 1,..,n.

Template Parameters
ResultMust be an fcppt::record::object.
FunctionA polymorphic function callable as fcppt::record::label_value_type<Result, L> (fcppt::record::element<L,T>) for every element<L,T> in Result.

◆ label_name()

template<typename Label >
std::string fcppt::record::label_name ( )
inline

Returns the name of a label as a string.

◆ make()

fcppt::record::object< fcppt::record::element< fcppt::record::label< fcppt::record::element_init_tag< Args > >, fcppt::record::element_init_type< Args > >... > fcppt::record::make ( Args &&... _args)
inlinenodiscard

Creates a record from an initializer list.

Args must be created using label{} = value expressions.

◆ map()

template<typename Record , typename Function >
fcppt::record::map_result< Record, Function > fcppt::record::map ( Record && _record,
Function const & _function )
inline

Maps a record using a function.

For every fcppt::record::element<L,T> in Record, _function(get<L>(_record)) is stored in the result type.

Template Parameters
RecordAn fcppt::record::object.
Functiona polymorphic function that can be called with every type in Record.
See also
fcppt::record::map_result

◆ multiply_disjoint()

template<typename Record1 , typename Record2 >
fcppt::record::disjoint_product< std::remove_cvref_t< Record1 >, std::remove_cvref_t< Record2 > > fcppt::record::multiply_disjoint ( Record1 && _record1,
Record2 && _record2 )

Creates the disjoint product of two records.

Template Parameters
Record1Must be an fcppt::record::object that is disjoint from Record2.
Record2Must be an fcppt::record::object that is disjoint from Record1.

◆ operator!=()

template<typename... Types1, typename... Types2>
bool fcppt::record::operator!= ( fcppt::record::object< Types1... > const & _record1,
fcppt::record::object< Types2... > const & _record2 )
inline

Compares two records for inequality.

Template Parameters
Types1Must be equivalent to Types2
Types2Must be equivalent to Types1

◆ operator<<()

template<typename Ch , typename Traits , typename... Elements>
std::basic_ostream< Ch, Traits > & fcppt::record::operator<< ( std::basic_ostream< Ch, Traits > & _stream,
fcppt::record::object< Elements... > const & _record )

Outputs a record to a stream.

◆ operator==()

template<typename... Types1, typename... Types2>
bool fcppt::record::operator== ( fcppt::record::object< Types1... > const & _record1,
fcppt::record::object< Types2... > const & _record2 )

Compares two records for equality.

Template Parameters
Types1Must be equivalent to Types2
Types2Must be equivalent to Types1

◆ permute()

template<typename Result , typename Arg >
Result fcppt::record::permute ( Arg && _arg)
inline

Permutes one record into another.

Template Parameters
ResultMust be equivalent to Arg, and must be an fcppt::record::object.
ArgMust be equivalent to Result, and must be an fcppt::record::object.

◆ set() [1/2]

template<typename Label , typename... Elements>
void fcppt::record::set ( fcppt::record::object< Elements... > & _arg,
fcppt::record::label_value_type< fcppt::record::object< Elements... >, Label > && _value )
inline

Sets an element in a record by move.

Moves _value to the element identified by Label in _arg.

◆ set() [2/2]

template<typename Label , typename... Elements>
void fcppt::record::set ( fcppt::record::object< Elements... > & _arg,
fcppt::record::label_value_type< fcppt::record::object< Elements... >, Label > const & _value )
inline

Sets an element in a record by copy.

Copies _value to the element identified by Label in _arg.

Variable Documentation

◆ all_disjoint_v

bool fcppt::record::all_disjoint_v = fcppt::record::all_disjoint<Records>::value
inlineconstexpr

Tests if multiple records have disjoint label sets.

See also
fcppt::record::all_disjoint

◆ are_disjoint_v

template<typename RecordL , typename RecordR >
bool fcppt::record::are_disjoint_v = fcppt::record::are_disjoint<RecordL, RecordR>::value
inlineconstexpr

Tests if two records have disjoint label sets.

See also
fcppt::record::are_disjoint

◆ are_equivalent_v

template<typename Record1 , typename Record2 >
bool fcppt::record::are_equivalent_v = fcppt::record::are_equivalent<Record1, Record2>::value
inlineconstexpr

Tests if two records have the same element maps.