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:
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';
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>
{
_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>
{
{ 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:
{
if (!(stream >> input))
{
throw std::runtime_error{"failure"};
}
})};
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:
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
|
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 |
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
-
◆ 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 >
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
-
Record | An fcppt::record::object. |
Function | a 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
-
◆ 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.