21 Metaprogramming library [meta]

21.4 Reflection [meta.reflection]

21.4.15 Reflection class definition generation [meta.reflection.define.aggregate]

namespace std::meta { struct data_member_options { struct name-type { // exposition only template<class T> requires constructible_from<u8string, T> consteval name-type(T&&); template<class T> requires constructible_from<string, T> consteval name-type(T&&); private: variant<u8string, string> contents; // exposition only }; optional<name-type> name; optional<int> alignment; optional<int> bit_width; bool no_unique_address = false; }; }
The classes data_member_options and data_member_options​::​name-type are consteval-only types ([basic.types.general]), and are not structural types ([temp.param]).
template<class T> requires constructible_from<u8string, T> consteval data_member_options::name-type(T&& value);
Effects: Initializes contents with u8string(std​::​forward<T>(value)).
template<class T> requires constructible_from<string, T> consteval data_member_options::name-type(T&& value);
Effects: Initializes contents with string(std​::​forward<T>(value)).
[Note 1: 
The class name-type allows the function data_member_spec to accept an ordinary string literal (or string_view, string, etc.)
or a UTF-8 string literal (or u8string_view, u8string, etc.)
equally well.
[Example 1: consteval void fn() { data_member_options o1 = {.name = "ordinary_literal_encoding"}; data_member_options o2 = {.name = u8"utf8_encoding"}; } — end example]
— end note]
consteval info data_member_spec(info type, data_member_options options);
Constant When:
  • dealias(type) represents eitehr an object type or a reference type;
  • if options.name contains a value, then:
    • holds_alternative<u8string>(options.name->contents) is true and get<u8string>(​options.name->​contents) contains a valid identifier ([lex.name]) that is not a keyword ([lex.key]) when interpreted with UTF-8, or
    • holds_alternative<string>(options.name->contents) is true and get<string>(
      options.name->contents)
      contains a valid identifier ([lex.name]) that is not a keyword ([lex.key]) when interpreted with the ordinary literal encoding;
    [Note 2: 
    The name corresponds to the spelling of an identifier token after phase 6 of translation ([lex.phases]).
    Lexical constructs like universal-character-names ([lex.universal.char]) are not processed and will cause evaluation to fail.
    For example, R"(\u03B1)" is an invalid identifier and is not interpreted as "α".
    — end note]
  • if options.name does not contain a value, then options.bit_width contains a value;
  • if options.bit_width contains a value V, then
    • is_integral_type(type) || is_enumeration_type(type) is true,
    • options.alignment does not contain a value,
    • options.no_unique_address is false, and
    • if V equals 0, then options.name does not contain a value; and
  • if options.alignment contains a value, it is an alignment value ([basic.align]) not less than alignment_of(type).
Returns: A reflection of a data member description ([class.mem.general]) where
  • T is the type represented by dealias(type),
  • N is either the identifier encoded by options.name or ⊥ if options.name does not contain a value,
  • A is either the alignment value held by options.alignment or ⊥ if options.alignment does not contain a value,
  • W is either the value held by options.bit_width or ⊥ if options.bit_width does not contain a value, and
  • NUA is the value held by options.no_unique_address.
[Note 3: 
The returned reflection value is primarily useful in conjunction with define_aggregate; it can also be queried by certain other functions in std​::​meta (e.g., type_of, identifier_of).
— end note]
consteval bool is_data_member_spec(info r);
Returns: true if r represents a data member description.
Otherwise, false.
template<reflection_range R = initializer_list<info>> consteval info define_aggregate(info class_type, R&& mdescrs);
Let C be the class represented by class_type and be the reflection value in mdescrs.
For every in mdescrs, let be the corresponding data member description represented by .
Constant When:
  • C is incomplete from every point in the evaluation context;
    [Note 4: 
    C can be a class template specialization for which there is a reachable definition of the class template.
    In this case, the injected declaration is an explicit specialization.
    — end note]
  • is_data_member_spec() is true for every ;
  • is_complete_type() is true for every ; and
  • for every pair where , if is not ⊥ and is not ⊥, then either:
    • != is true or
    • != u8"_" is true.
      [Note 5: 
      C can be a class template specialization for which there is a reachable definition of the class template.
      In this case, the injected declaration is an explicit specialization.
      — end note]
Effects: Produces an injected declaration C ([expr.const]) that defines C and has properties as follows:
  • The target scope of D is the scope to which C belongs ([basic.scope.scope]).
  • The locus of D follows immediately after the core constant expression currently under evaluation.
  • The characteristic sequence of D ([expr.const]) is the sequence of reflection values .
  • If C is a specialization of a templated class T, and C is not a local class, then D is an explicit specialization of T.
  • For each , there is a corresponding entity belonging to the class cope of D with the following properties:
    • If is ⊥, is an unnamed bit-field.
      Otherwise, is a non-static data member whose name is the identifier determined by the character seqeunce encoed by in UTF-8.
    • The type of is .
    • is declared with the attribute [[no_unique_address]] if and only if is true.
    • If is not ⊥, is a bit-field whose width is that value.
      Otherwise, is not a bit-field.
    • If is not ⊥, has the alignment-specifier alignas().
      Otherwise, has no alignment-specifier.
  • For every in mdescrs such that , the declaration corresponding to precedes the declaration corresponding to .
Returns: class_type.