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;
};
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:
A record element is represented by fcppt::record::element. It gets a label together with a type as its template parameters:
using age_element = fcppt::record::element<age, int>;
using name_element = fcppt::record::element<name, std::string>;
Finally, a record object consists of a list of elements:
using person = fcppt::record::object<age_element, name_element>;
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';
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
<< ": "
}
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)
{
[&_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
};
person const test_person{
age{} = 42,
age{} = 10
};
person const test_person{
age{} = 42,
};
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>)
{
if (!(stream >> input))
{
throw std::runtime_error{"failure"};
}
return std::move(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:
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...>>
{
using type = fcppt::record::object<sprite_element<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
|
| 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.
|
|
| 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.
|
◆ FCPPT_RECORD_MAKE_LABEL
| #define FCPPT_RECORD_MAKE_LABEL |
( |
| name | ) |
|
Value: FCPPT_RECORD_DETAIL_MAKE_TAG(name); \
\
Creates an fcppt::record::label.
Creates an fcppt::record::label, passing it a unique, implementation-defined tag type.
- Parameters
-
| name | The 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> \
>
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
-
| name | The name of the label type. |
| arg | The type of the template parameter. |
◆ all_disjoint
Initial value: std::is_same<
Records,
Records,
Tests if multiple records have disjoint label sets.
◆ are_disjoint
template<typename RecordL, typename RecordR>
Initial value: std::is_same<
fcppt::mpl::set::
Tests if two records have disjoint label sets.
◆ are_equivalent
template<typename Record1, typename Record2>
Initial value:
Tests if two records have the same element maps.
◆ disjoint_product
template<typename RecordL, typename RecordR>
The product of two disjoint records.
◆ element_init_tag
◆ element_init_type
◆ element_map
template<typename Record>
Initial value:
A metafunction computing the element map of a record.
- Template Parameters
-
◆ element_tag_tuple
template<typename Record>
◆ element_to_label
template<typename Element>
◆ element_to_type
template<typename Element>
Initial value:
typename fcppt::record::detail::element_to_type<std::remove_cv_t<Element>>::type
Extracts the label of an element.
- Template Parameters
-
◆ element_vector
template<typename Record>
A metafunction returning the elements of record as an MPL vector.
- Template Parameters
-
◆ from_list
◆ has_label
template<typename Record, typename Label>
◆ is_vararg_ctor
template<typename... Args>
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>
Initial value:
fcppt::record::detail::label_list<fcppt::record::element_vector<Record>>>
The set of labels of a record.
- Template Parameters
-
◆ label_value_type
template<typename Record, typename Label>
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>
Initial value:
Maps the elements of a vector using a metafunction.
- Template Parameters
-
◆ map_result
template<typename Record, typename Function>
Initial value:
The result of mapping a record.
◆ unique
Removes duplicates from a list.
◆ get() [1/2]
template<typename Label, typename... Elements>
Gets an element from a record.
Returns the element identified by Label from _arg.
◆ get() [2/2]
template<typename Label, typename... Elements>
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 |
◆ label_name()
template<typename Label>
| std::string fcppt::record::label_name |
( |
| ) |
|
|
inline |
Returns the name of a label as a string.
◆ make()
Creates a record from an initializer list.
Args must be created using label{} = value expressions.
◆ map()
template<typename Record, typename Function>
◆ 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
-
◆ operator!=()
template<typename... Types1, typename... Types2>
Compares two records for inequality.
- Template Parameters
-
| Types1 | Must be equivalent to Types2 |
| Types2 | Must 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>
Compares two records for equality.
- Template Parameters
-
| Types1 | Must be equivalent to Types2 |
| Types2 | Must be equivalent to Types1 |
◆ permute()
template<typename Result, typename Arg>
| Result fcppt::record::permute |
( |
Arg && | _arg | ) |
|
|
inline |
Permutes one record into another.
- Template Parameters
-
◆ set() [1/2]
template<typename Label, typename... Elements>
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>
Sets an element in a record by copy.
Copies _value to the element identified by Label in _arg.
◆ all_disjoint_v
◆ are_disjoint_v
template<typename RecordL, typename RecordR>
◆ are_equivalent_v
template<typename Record1, typename Record2>
Tests if two records have the same element maps.