From 5fc198da8e106583d568b8a97cda335dd551486a Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Sun, 3 Nov 2024 13:23:19 -0600 Subject: [PATCH] Removing reflect_invoke --- 2996_reflection/p2996r8.html | 3494 +++++++++++++++------------------ 2996_reflection/reflection.md | 174 +- 2 files changed, 1593 insertions(+), 2075 deletions(-) diff --git a/2996_reflection/p2996r8.html b/2996_reflection/p2996r8.html index 94863582..09ec75d4 100644 --- a/2996_reflection/p2996r8.html +++ b/2996_reflection/p2996r8.html @@ -641,8 +641,6 @@

Contents

  • 3.16 Named Tuple
  • 3.17 Compile-Time Ticket Counter
  • -
  • 3.18 Emulating typeful -reflection
  • 4 Proposed Features
  • 4.5 ODR Concerns
  • @@ -953,8 +949,9 @@

    spaceship, and ampersand_and -> ampersand_ampersand) -
  • removed define_static_array and -define_static_string
  • +
  • removed define_static_array, +define_static_string, and +reflect_invoke
  • clarified that sizeof(std::meta::info) ==sizeof(void *)`
  • clarified that @@ -2445,104 +2442,6 @@

    EDG, Clang.

    -

    3.18 Emulating typeful reflection

    -

    Although we believe a single opaque std::meta::info -type to be the best and most scalable foundation for reflection, we -acknowledge the desire expressed by SG7 for future support for “typeful -reflection”. The following demonstrates one possible means of assembling -a typeful reflection library, in which different classes of reflections -are represented by distinct types, on top of the facilities proposed -here.

    -
    -
    -
    // Represents a 'std::meta::info' constrained by a predicate.
    -template <std::meta::info Pred>
    -  requires (std::predicate<[:type_of(Pred):], std::meta::info>)
    -struct metatype {
    -  std::meta::info value;
    -
    -  // Construction is ill-formed unless predicate is satisfied.
    -  consteval metatype(std::meta::info r) : value(r) {
    -    if (![:Pred:](r))
    -      throw "Reflection is not a member of this metatype";
    -  }
    -
    -  // Cast to 'std::meta::info' allows values of this type to be spliced.
    -  consteval operator std::meta::info() const { return value; }
    -
    -  static consteval bool check(std::meta::info r) { return [:Pred:](r); }
    -};
    -
    -// Type representing a "failure to match" any known metatypes.
    -struct unmatched {
    -  consteval unmatched(std::meta::info) {}
    -  static consteval bool check(std::meta::info) { return true; }
    -};
    -
    -// Returns the given reflection "enriched" with a more descriptive type.
    -template <typename... Choices>
    -consteval std::meta::info enrich(std::meta::info r) {
    -  // Because we control the type, we know that the constructor taking info is
    -  // the first constructor. The copy/move constructors are added at the }, so
    -  // will be the last ones in the list.
    -  std::array ctors = {
    -    *(members_of(^Choices) | std::views::filter(std::meta::is_constructor)).begin()...,
    -    *(members_of(^unmatched) | std::views::filter(std::meta::is_constructor)).begin()
    -  };
    -  std::array checks = {^Choices::check..., ^unmatched::check};
    -
    -  for (auto [check, ctor] : std::views::zip(checks, ctors))
    -    if (extract<bool>(reflect_invoke(check, {reflect_value(r)})))
    -      return reflect_invoke(ctor, {reflect_value(r)});
    -
    -  std::unreachable();
    -}
    -
    -
    -

    We can leverage this machinery to select different function overloads -based on the “type” of reflection provided as an argument.

    -
    -
    -
    using type_t = metatype<^std::meta::is_type>;
    -using template_t = metatype<^std::meta::is_template>;
    -
    -// Example of a function overloaded for different "types" of reflections.
    -void PrintKind(type_t) { std::println("type"); }
    -void PrintKind(template_t) { std::println("template"); }
    -void PrintKind(unmatched) { std::println("unknown kind"); }
    -
    -int main() {
    -  // Classifies any reflection as one of: Type, Function, or Unmatched.
    -  auto enrich = [](std::meta::info r) { return ::enrich<type_t,
    -                                                        template_t>(r); };
    -
    -  // Demonstration of using 'enrich' to select an overload.
    -  PrintKind([:enrich(^metatype):]);                   // "template"
    -  PrintKind([:enrich(^type_t):]);                     // "type"
    -  PrintKind([:enrich(std::meta::reflect_value(3):]);  // "unknown kind"
    -}
    -
    -
    -

    Note that the metatype class can -be generalized to wrap values of any literal type, or to wrap multiple -values of possibly different types. This has been used, for instance, to -select compile-time overloads based on: whether two integers share the -same parity, the presence or absence of a value in an -optional, the type of the value held -by a variant or an -any, or the syntactic form of a -compile-time string.

    -

    Achieving the same in C++23, with the same generality, would require -spelling the argument(s) twice: first to obtain a “classification tag” -to use as a template argument, and again to call the function, i.e.,

    -
    -
    -
    Printer::PrintKind<classify(^int)>(^int).
    -// or worse...
    -fn<classify(Arg1, Arg2, Arg3)>(Arg1, Arg2, Arg3).
    -
    -
    -

    On Compiler Explorer: Clang.

    4 Proposed Features

    4.1 The Reflection Operator @@ -2592,17 +2491,17 @@

    template <int P1, const int &P2> void fn() {}
    -
    -static constexpr int p[2] = {1, 2};
    -constexpr auto spec = ^fn<p[0], p[1]>;
    -
    -static_assert(is_value(template_arguments_of(spec)[0]));
    -static_assert(is_object(template_arguments_of(spec)[1]));
    -static_assert(!is_variable(template_arguments_of(spec)[1]));
    -
    -static_assert([:template_arguments_of(spec)[0]:] == 1);
    -static_assert(&[:template_arguments_of(spec)[1]:] == &p[1]);
    +
    template <int P1, const int &P2> void fn() {}
    +
    +static constexpr int p[2] = {1, 2};
    +constexpr auto spec = ^fn<p[0], p[1]>;
    +
    +static_assert(is_value(template_arguments_of(spec)[0]));
    +static_assert(is_object(template_arguments_of(spec)[1]));
    +static_assert(!is_variable(template_arguments_of(spec)[1]));
    +
    +static_assert([:template_arguments_of(spec)[0]:] == 1);
    +static_assert(&[:template_arguments_of(spec)[1]:] == &p[1]);

    Such reflections cannot generally be obtained using the ^-operator, but the std::meta::reflect_value @@ -2679,7 +2578,7 @@

    4.2
    -
    typename[: ^:: :] x = 0;  // Error.
    +
    typename[: ^:: :] x = 0;  // Error.

    4.2.1 Addressed Splicing

    @@ -2721,17 +2620,17 @@

    -
    struct C {
    -    template <class T> void f(T); // #1
    -    void f(int); // #2
    -};
    -
    -void (C::*p1)(int) = &C::f;  // error: ambiguous
    -
    -constexpr auto f1 = members_of(^C, /* function templates named f */)[0];
    -constexpr auto f2 = members_of(^C, /* functions named f */)[0];
    -void (C::*p2)(int) = &[:f1:]; // ok, refers to C::f<int> (#1)
    -void (C::*p3)(int) = &[:f2:]; // ok, refers to C::f      (#2)
    +
    struct C {
    +    template <class T> void f(T); // #1
    +    void f(int); // #2
    +};
    +
    +void (C::*p1)(int) = &C::f;  // error: ambiguous
    +
    +constexpr auto f1 = members_of(^C, /* function templates named f */)[0];
    +constexpr auto f2 = members_of(^C, /* functions named f */)[0];
    +void (C::*p2)(int) = &[:f1:]; // ok, refers to C::f<int> (#1)
    +void (C::*p3)(int) = &[:f2:]; // ok, refers to C::f      (#2)

    Another interesting question is what does this mean when @@ -2739,9 +2638,9 @@

    -
    struct X {
    -    X(int, int);
    -};
    +
    struct X {
    +    X(int, int);
    +};

    And let rc be a reflection of the @@ -2751,18 +2650,18 @@

    rd should be as follows:

    -
    auto x = [: rc :](1, 2); // gives you an X
    -x.[: rd :]();            // destroys it
    +
    auto x = [: rc :](1, 2); // gives you an X
    +x.[: rd :]();            // destroys it

    Or, with pointers:

    -
    auto pc = &[: rc :];
    -auto pd = &[: rd :];
    -
    -auto x = (*pc)(1, 2);   // gives you an X
    -(x.*pd)();              // destroys it
    +
    auto pc = &[: rc :];
    +auto pd = &[: rd :];
    +
    +auto x = (*pc)(1, 2);   // gives you an X
    +(x.*pd)();              // destroys it

    That is, splicing a constructor behaves like a free function that @@ -2797,14 +2696,14 @@

    4.2.2.2 Splicing namespaces in namespace definitions

    -
    namespace A {}
    -constexpr std::meta::info NS_A = ^A;
    -
    -namespace B {
    -  namespace [:NS_A:] {
    -    void fn();  // Is this '::A::fn' or '::B::A::fn' ?
    -  }
    -}
    +
    namespace A {}
    +constexpr std::meta::info NS_A = ^A;
    +
    +namespace B {
    +  namespace [:NS_A:] {
    +    void fn();  // Is this '::A::fn' or '::B::A::fn' ?
    +  }
    +}

    We found no satisfying answer as to how to interpret examples like the one given above. Neither did we find motivating use cases: many of the “interesting” uses for reflections of namespaces are either to @@ -2816,14 +2715,14 @@

    4.2.2.3 Splicing namespaces in using-directives and using-enum-declarators

    -
    template <std::meta::info R> void fn1() {
    -  using enum [:R:]::EnumCls;  // #1
    -  // ...
    -}
    -template <std::meta::info R> void fn2() {
    -  using namespace [:R:];      // #2
    -  // ...
    -}
    +
    template <std::meta::info R> void fn1() {
    +  using enum [:R:]::EnumCls;  // #1
    +  // ...
    +}
    +template <std::meta::info R> void fn2() {
    +  using namespace [:R:];      // #2
    +  // ...
    +}

    C++20 already disallowed dependent enumeration types from appearing in using-enum-declarators (as in #1), as it would otherwise force the parser to consider every subsequent identifier as possibly a @@ -2833,11 +2732,11 @@

    4.2.2.4 Splicing concepts in declarations of template parameters

    -
    template <typename T> concept C = requires { requires true; };
    -
    -template <std::meta::info R> struct Outer {
    -  template <template [:R:] S> struct Inner { /* ... */ };
    -};
    +
    template <typename T> concept C = requires { requires true; };
    +
    +template <std::meta::info R> struct Outer {
    +  template <template [:R:] S> struct Inner { /* ... */ };
    +};

    What kind of parameter is S? If R represents a class template, then it is a non-type template parameter of deduced type, but if @@ -2851,10 +2750,10 @@

    template <std::meta::info R> struct Outer {
    -  template <typename T> requires template [:R:]<T>
    -  struct Inner { /* ... */ };
    -};
    +
    template <std::meta::info R> struct Outer {
    +  template <typename T> requires template [:R:]<T>
    +  struct Inner { /* ... */ };
    +};

    We are resolving this ambiguity by simply disallowing a reflection of a concept, whether dependent or otherwise, from being spliced in the declaration of a template parameter (thus in the above example, the @@ -2862,9 +2761,9 @@

    4.2.2.5 Splicing class members as designators in designated-initializer-lists

    -
    struct S { int a; };
    -
    -constexpr S s = {.[:^S::a:] = 2};
    +
    struct S { int a; };
    +
    +constexpr S s = {.[:^S::a:] = 2};

    Although we would like for splices of class members to be usable as designators in an initializer-list, we lack implementation experience with the syntax and would first like to verify that there are no issues @@ -2895,28 +2794,28 @@

    -
    template <typename T>
    -constexpr auto struct_to_tuple(T const& t) {
    -  constexpr auto members = nonstatic_data_members_of(^T);
    -
    -  constexpr auto indices = []{
    -    std::array<int, members.size()> indices;
    -    std::ranges::iota(indices, 0);
    -    return indices;
    -  }();
    -
    -  constexpr auto [...Is] = indices;
    -  return std::make_tuple(t.[: members[Is] :]...);
    -}
    +
    template <typename T>
    +constexpr auto struct_to_tuple(T const& t) {
    +  constexpr auto members = nonstatic_data_members_of(^T);
    +
    +  constexpr auto indices = []{
    +    std::array<int, members.size()> indices;
    +    std::ranges::iota(indices, 0);
    +    return indices;
    +  }();
    +
    +  constexpr auto [...Is] = indices;
    +  return std::make_tuple(t.[: members[Is] :]...);
    +}
    -
    template <typename T>
    -constexpr auto struct_to_tuple(T const& t) {
    -  constexpr auto members = nonstatic_data_members_of(^T);
    -  return std::make_tuple(t.[: ...members :]...);
    -}
    +
    template <typename T>
    +constexpr auto struct_to_tuple(T const& t) {
    +  constexpr auto members = nonstatic_data_members_of(^T);
    +  return std::make_tuple(t.[: ...members :]...);
    +}
    @@ -2929,13 +2828,13 @@

    pack of splices. So the above expression

    -
    make_tuple(t.[: ... members :]...)
    +
    make_tuple(t.[: ... members :]...)

    would evaluate as

    -
    make_tuple(t.[:members[0]:], t.[:members[1]:], ..., t.[:members[N-1]:])
    +
    make_tuple(t.[:members[0]:], t.[:members[1]:], ..., t.[:members[N-1]:])

    This is a very useful facility indeed!

    @@ -2950,13 +2849,13 @@

    Which is enough for a tolerable implementation:

    -
    template <typename T>
    -constexpr auto struct_to_tuple(T const& t) {
    -  constexpr auto members = nonstatic_data_members_of(^T);
    -  return with_size<members.size()>([&](auto... Is){
    -    return std::make_tuple(t.[: members[Is] :]...);
    -  });
    -}
    +
    template <typename T>
    +constexpr auto struct_to_tuple(T const& t) {
    +  constexpr auto members = nonstatic_data_members_of(^T);
    +  return with_size<members.size()>([&](auto... Is){
    +    return std::make_tuple(t.[: members[Is] :]...);
    +  });
    +}

    4.2.4 Syntax discussion

    @@ -3067,11 +2966,11 @@

    4.3
    -
    namespace std {
    -  namespace meta {
    -    using info = decltype(^::);
    -  }
    -}
    +
    namespace std {
    +  namespace meta {
    +    using info = decltype(^::);
    +  }
    +}

    In our initial proposal a value of type std::meta::info @@ -3110,14 +3009,14 @@

    4.3
    -
    template <typename T> void fn(T) {}
    -
    -void g() {
    -  constexpr auto call = ^(fn(42));
    -  static_assert(
    -      template_arguments_of(function_of(call))[0] ==
    -      ^int);
    -}
    +
    template <typename T> void fn(T) {}
    +
    +void g() {
    +  constexpr auto call = ^(fn(42));
    +  static_assert(
    +      template_arguments_of(function_of(call))[0] ==
    +      ^int);
    +}

    Previous revisions of this proposal suggested limited support for @@ -3133,17 +3032,17 @@

    -
    static_assert(^int == ^int);
    -static_assert(^int != ^const int);
    -static_assert(^int != ^int &);
    -
    -using Alias = int;
    -static_assert(^int != ^Alias);
    -static_assert(^int == dealias(^Alias));
    -
    -namespace AliasNS = ::std;
    -static_assert(^::std != ^AliasNS);
    -static_assert(^:: == parent_of(^::std));
    +
    static_assert(^int == ^int);
    +static_assert(^int != ^const int);
    +static_assert(^int != ^int &);
    +
    +using Alias = int;
    +static_assert(^int != ^Alias);
    +static_assert(^int == dealias(^Alias));
    +
    +namespace AliasNS = ::std;
    +static_assert(^::std != ^AliasNS);
    +static_assert(^:: == parent_of(^::std));

    When the @@ -3153,11 +3052,11 @@

    -
    int x;
    -struct S { static int y; };
    -static_assert(^x == ^x);
    -static_assert(^x != ^S::y);
    -static_assert(^S::y == static_data_members_of(^S)[0]);
    +
    int x;
    +struct S { static int y; };
    +static_assert(^x == ^x);
    +static_assert(^x != ^S::y);
    +static_assert(^S::y == static_data_members_of(^S)[0]);

    Special rules apply when comparing certain kinds of reflections. A @@ -3167,17 +3066,17 @@

    -
    using Alias1 = int;
    -using Alias2 = int;
    -consteval std::meta::info fn() {
    -  using Alias1 = int;
    -  return ^Alias;
    -}
    -static_assert(^Alias1 == ^Alias1);
    -static_assert(^Alias1 != ^int);
    -static_assert(^Alias1 != ^Alias2);
    -static_assert(^Alias1 != fn());
    -}
    +
    using Alias1 = int;
    +using Alias2 = int;
    +consteval std::meta::info fn() {
    +  using Alias1 = int;
    +  return ^Alias;
    +}
    +static_assert(^Alias1 == ^Alias1);
    +static_assert(^Alias1 != ^int);
    +static_assert(^Alias1 != ^Alias2);
    +static_assert(^Alias1 != fn());
    +}

    A reflection of an object (including variables) does not compare @@ -3185,17 +3084,17 @@

    -
    constexpr int i = 42, j = 42;
    -
    -constexpr std::meta::info r = ^i, s = ^i;
    -static_assert(r == r && r == s);
    -
    -static_assert(^i != ^j);  // 'i' and 'j' are different entities.
    -static_assert(value_of(^i) == value_of(^j));  // Two equivalent values.
    -static_assert(^i != std::meta::reflect_object(i))  // A variable is distinct from the
    -                                                   // object it designates.
    -static_assert(^i != std::meta::reflect_value(42));  // A reflection of an object
    -                                                    // is not the same as its value.
    +
    constexpr int i = 42, j = 42;
    +
    +constexpr std::meta::info r = ^i, s = ^i;
    +static_assert(r == r && r == s);
    +
    +static_assert(^i != ^j);  // 'i' and 'j' are different entities.
    +static_assert(value_of(^i) == value_of(^j));  // Two equivalent values.
    +static_assert(^i != std::meta::reflect_object(i))  // A variable is distinct from the
    +                                                   // object it designates.
    +static_assert(^i != std::meta::reflect_value(42));  // A reflection of an object
    +                                                    // is not the same as its value.

    4.3.2 The associated @@ -3208,10 +3107,10 @@

    -
    #include <meta>
    -struct S {};
    -std::string name2 = std::meta::identifier_of(^S);  // Okay.
    -std::string name1 = identifier_of(^S);             // Also okay.
    +
    #include <meta>
    +struct S {};
    +std::string name2 = std::meta::identifier_of(^S);  // Okay.
    +std::string name1 = identifier_of(^S);             // Also okay.

    Default constructing or value-initializing an object of type std::meta::info @@ -3221,10 +3120,10 @@

    -
    #include <meta>
    -struct S {};
    -static_assert(std::meta::info() == std::meta::info());
    -static_assert(std::meta::info() != ^S);
    +
    #include <meta>
    +struct S {};
    +static_assert(std::meta::info() == std::meta::info());
    +static_assert(std::meta::info() != ^S);

    4.4 Metafunctions

    @@ -3249,13 +3148,13 @@

    -
    #include <meta>
    -struct S;
    -
    -void g() {
    -  static_assert(is_type(define_class(^S, {})));
    -  S s;  // S should be defined at this point.
    -}
    +
    #include <meta>
    +struct S;
    +
    +void g() {
    +  static_assert(is_type(define_class(^S, {})));
    +  S s;  // S should be defined at this point.
    +}

    Hence this proposal also introduces constraints on constant @@ -3327,9 +3226,9 @@

    std::expected:

    -
    template <typename T>
    -  requires (template_of(^T) == ^std::optional)
    -void foo();
    +
    template <typename T>
    +  requires (template_of(^T) == ^std::optional)
    +void foo();
      @@ -3411,14 +3310,14 @@

    Example 2: -
    template <typename T> void fn() requires (^T != ^int);
    -template <typename T> void fn() requires (^T == ^int);
    -template <typename T> void fn() requires (sizeof(T) == sizeof(int));
    -
    -constexpr auto R = ^fn<char>;     // OK
    -constexpr auto S = ^fn<int>;      // error: cannot reflect an overload set
    -
    -constexpr auto r = ^std::vector;  // OK
    +
    template <typename T> void fn() requires (^T != ^int);
    +template <typename T> void fn() requires (^T == ^int);
    +template <typename T> void fn() requires (sizeof(T) == sizeof(int));
    +
    +constexpr auto R = ^fn<char>;     // OK
    +constexpr auto S = ^fn<int>;      // error: cannot reflect an overload set
    +
    +constexpr auto r = ^std::vector;  // OK
    — end example ]
    @@ -6075,24 +5921,24 @@

    7.7 Example 1: -
    template <class> struct RV {};
    -
    -// instantiations of 'T::f(0)' are not plainly constant-evaluated
    -template <class T> RV<T::f(0)> check(int);
    -
    -consteval bool cfn(int) { return true; }
    -
    -template <int V> requires (cfn(V))  // cfn(V) is not plainly constant-evaluated
    -consteval int g() {
    -    if constexpr (cfn(V+1)) {       // cfn(V+1) is plainly constant-evaluated
    -        return cfn(V+2);            // cfn(V+2) is plainly constant-evaluated
    -    } else {
    -        return 0;
    -    }
    -}
    -
    -constexpr bool b1 = !cfn(1);        // !cfn(1) is plainly constant-evaluated
    -const bool b2 = cfn(2);             // cfn(2) is not plainly constant-evaluated
    +
    template <class> struct RV {};
    +
    +// instantiations of 'T::f(0)' are not plainly constant-evaluated
    +template <class T> RV<T::f(0)> check(int);
    +
    +consteval bool cfn(int) { return true; }
    +
    +template <int V> requires (cfn(V))  // cfn(V) is not plainly constant-evaluated
    +consteval int g() {
    +    if constexpr (cfn(V+1)) {       // cfn(V+1) is plainly constant-evaluated
    +        return cfn(V+2);            // cfn(V+2) is plainly constant-evaluated
    +    } else {
    +        return 0;
    +    }
    +}
    +
    +constexpr bool b1 = !cfn(1);        // !cfn(1) is plainly constant-evaluated
    +const bool b2 = cfn(2);             // cfn(2) is not plainly constant-evaluated
    — end example ] @@ -6177,33 +6023,33 @@

    7.7 Example 2: -
    consteval bool make_decl(int);      // calling 'make_decl(n)' produces a declaration
    -
    -template <int R> requires (make_decl(R))
    -  bool tfn();
    -
    -constexpr bool b1 = !make_decl(1);  // OK, constexpr variable so this is plainly
    -                                    // constant evaluated
    -
    -bool b2 = !make_decl(2);            // error: initializer !make_decl(42) produced
    -                                    // a declaration but is not plainly constant
    -                                    // evaluated
    -
    -constexpr bool b3 = tfn<3>();       // error: the invocation of make_decl(R) in the
    -                                    // requires clause produced a declaration but is
    -                                    // not plainly constant evaluated
    -
    -consteval int *not_constant() {
    -  make_decl(4);
    -  return new int {};
    -}
    -constexpr bool b4 = [] {
    -  int *p = not_constant();          // error: not_constant() produces a declaration
    -                                    // in an immediate-escalated function, but is
    -                                    // not plainly constant-evalauted.
    -  delete p;
    -  return true;
    -}();
    +
    consteval bool make_decl(int);      // calling 'make_decl(n)' produces a declaration
    +
    +template <int R> requires (make_decl(R))
    +  bool tfn();
    +
    +constexpr bool b1 = !make_decl(1);  // OK, constexpr variable so this is plainly
    +                                    // constant evaluated
    +
    +bool b2 = !make_decl(2);            // error: initializer !make_decl(42) produced
    +                                    // a declaration but is not plainly constant
    +                                    // evaluated
    +
    +constexpr bool b3 = tfn<3>();       // error: the invocation of make_decl(R) in the
    +                                    // requires clause produced a declaration but is
    +                                    // not plainly constant evaluated
    +
    +consteval int *not_constant() {
    +  make_decl(4);
    +  return new int {};
    +}
    +constexpr bool b4 = [] {
    +  int *p = not_constant();          // error: not_constant() produces a declaration
    +                                    // in an immediate-escalated function, but is
    +                                    // not plainly constant-evalauted.
    +  delete p;
    +  return true;
    +}();
    — end example ]

    24 @@ -6235,10 +6081,10 @@

    9.2.9.3
    -
      computed-type-specifier:
    -     decltype-specifier
    -     pack-index-specifier
    -+    splice-type-specifier
    +
      computed-type-specifier:
    +     decltype-specifier
    +     pack-index-specifier
    ++    splice-type-specifier
    @@ -6250,8 +6096,8 @@

    9.2.9*
    -
    +  splice-type-specifier
    -+      typenameopt splice-specifier
    +
    +  splice-type-specifier
    ++      typenameopt splice-specifier

    1 The typename @@ -6369,13 +6215,13 @@

    9.7.2
    -
      using-enum-declaration:
    -     using enum using-enum-declarator ;
    -
    -  using-enum-declarator:
    -     nested-name-specifieropt identifier
    -     nested-name-specifieropt simple-template-id
    -+    splice-specifier
    +
      using-enum-declaration:
    +     using enum using-enum-declarator ;
    +
    +  using-enum-declarator:
    +     nested-name-specifieropt identifier
    +     nested-name-specifieropt simple-template-id
    ++    splice-specifier

    @@ -6405,15 +6251,15 @@

    9.8.3
    -
      namespace-alias:
    -      identifier
    -
    -  namespace-alias-definition:
    -      namespace identifier = qualified-namespace-specifier
    -
    -  qualified-namespace-specifier:
    -      nested-name-specifieropt namespace-name
    -+     splice-specifier
    +
      namespace-alias:
    +      identifier
    +
    +  namespace-alias-definition:
    +      namespace identifier = qualified-namespace-specifier
    +
    +  qualified-namespace-specifier:
    +      nested-name-specifieropt namespace-name
    ++     splice-specifier
    @@ -6459,9 +6305,9 @@

    9.8.4
    -
      using-directive:
    --    attribute-specifier-seqopt using namespace nested-name-specifieropt namespace-name
    -+    attribute-specifier-seqopt using namespace qualified-namespace-specifier
    +
      using-directive:
    +-    attribute-specifier-seqopt using namespace nested-name-specifieropt namespace-name
    ++    attribute-specifier-seqopt using namespace qualified-namespace-specifier
    @@ -6517,10 +6363,10 @@

    -
      attribute-specifier:
    -     [ [ attribute-using-prefixopt attribute-list ] ]
    -+    [ [ using attribute-namespace :] ]
    -     alignment-specifier
    +
      attribute-specifier:
    +     [ [ attribute-using-prefixopt attribute-list ] ]
    ++    [ [ using attribute-namespace :] ]
    +     alignment-specifier
    @@ -6528,13 +6374,13 @@

    -
      balanced-token :
    -      ( balanced-token-seqopt )
    -      [ balanced-token-seqopt ]
    -      { balanced-token-seqopt }
    --     any token other than a parenthesis, a bracket, or a brace
    -+     [: balanced-token-seqopt :]
    -+     any token other than (, ), [, ], {, }, [:, or :]
    +
      balanced-token :
    +      ( balanced-token-seqopt )
    +      [ balanced-token-seqopt ]
    +      { balanced-token-seqopt }
    +-     any token other than a parenthesis, a bracket, or a brace
    ++     [: balanced-token-seqopt :]
    ++     any token other than (, ), [, ], {, }, [:, or :]
    @@ -6626,8 +6472,8 @@

    12.5 T is a pointer-to-member type, std::meta::info, or std​::​nullptr_t, there exist candidate operator functions of the form

    -
    bool operator==(T, T);
    -bool operator!=(T, T);
    +
    bool operator==(T, T);
    +bool operator!=(T, T);

    13.2 [temp.param] Template @@ -6651,22 +6497,22 @@

    1
    -
    + splice-template-name:
    -+     template splice-specifier
    -+
    -+ splice-template-argument:
    -+     splice-specifier
    -+
    -  template-name:
    -      identifier
    -+     splice-template-name
    -
    -  template-argument:
    -      constant-expression
    -      type-id
    -      id-expression
    -      braced-init-list
    -+     splice-template-argument
    +
    + splice-template-name:
    ++     template splice-specifier
    ++
    ++ splice-template-argument:
    ++     splice-specifier
    ++
    +  template-name:
    +      identifier
    ++     splice-template-name
    +
    +  template-argument:
    +      constant-expression
    +      type-id
    +      id-expression
    +      braced-init-list
    ++     splice-template-argument
    @@ -6727,20 +6573,20 @@

    1
    Example 1:
    -
    struct X {
    -  template<std::size_t> X* alloc();
    -  template<std::size_t> static X* adjust();
    -};
    -template<class T> void f(T* p) {
    -  T* p1 = p->alloc<200>();              // error: < means less than
    -  T* p2 = p->template alloc<200>();     // OK, < starts template argument list
    -  T::adjust<100>();                     // error: < means less than
    -  T::template adjust<100>();            // OK, < starts template argument list
    -
    -+ static constexpr auto r = ^T::adjust;
    -+ T* p3 = [:r:]<200>();                 // error: < means less than
    -+ T* p4 = template [:r:]<200>();        // OK, < starts template argument list
    -}
    +
    struct X {
    +  template<std::size_t> X* alloc();
    +  template<std::size_t> static X* adjust();
    +};
    +template<class T> void f(T* p) {
    +  T* p1 = p->alloc<200>();              // error: < means less than
    +  T* p2 = p->template alloc<200>();     // OK, < starts template argument list
    +  T::adjust<100>();                     // error: < means less than
    +  T::template adjust<100>();            // OK, < starts template argument list
    +
    ++ static constexpr auto r = ^T::adjust;
    ++ T* p3 = [:r:]<200>();                 // error: < means less than
    ++ T* p4 = template [:r:]<200>();        // OK, < starts template argument list
    +}
    — end example ]
    @@ -6781,16 +6627,16 @@

    13.4.1 Example 2:
    -
      template<class T> void f();
    -  template<int I> void f();
    -
    -  void g() {
    -    f<int()>();       // int() is a type-id: call the first f()
    -
    -+   constexpr int x = 42;
    -+   f<[:^int:]>();    // splice-template-argument: calls the first f()
    -+   f<[:^x:]>();      // splice-template-argument: calls the second f()
    -  }
    +
      template<class T> void f();
    +  template<int I> void f();
    +
    +  void g() {
    +    f<int()>();       // int() is a type-id: call the first f()
    +
    ++   constexpr int x = 42;
    ++   f<[:^int:]>();    // splice-template-argument: calls the first f()
    ++   f<[:^x:]>();      // splice-template-argument: calls the second f()
    +  }
    — end example ] @@ -6883,9 +6729,9 @@

    13.7.9
    -
      concept-name:
    -    identifier
    -+   splice-template-name
    +
      concept-name:
    +    identifier
    ++   splice-template-name
    @@ -6909,19 +6755,19 @@

    13.8.
    -
         literal
    -     sizeof unary-expression
    -     sizeof ( type-id )
    -     sizeof ... ( identifier )
    -     alignof ( type-id )
    -     typeid ( expression )
    -     typeid ( type-id )
    -     ::opt delete cast-expression
    -     ::opt delete [ ] cast-expression
    -     throw assignment-expressionopt
    -     noexcept ( expression )
    -     requires-expression
    -+    reflect-expression
    +
         literal
    +     sizeof unary-expression
    +     sizeof ( type-id )
    +     sizeof ... ( identifier )
    +     alignof ( type-id )
    +     typeid ( expression )
    +     typeid ( type-id )
    +     ::opt delete cast-expression
    +     ::opt delete [ ] cast-expression
    +     throw assignment-expressionopt
    +     noexcept ( expression )
    +     requires-expression
    ++    reflect-expression
    @@ -6957,12 +6803,12 @@

    Expressions of the following form are value-dependent if the unary-expression or expression is type-dependent or the type-id is dependent:

    -
    sizeof unary-expression
    -sizeof ( type-id )
    -typeid ( expression )
    -typeid ( type-id )
    -alignof ( type-id )
    -noexcept ( expression )
    +
    sizeof unary-expression
    +sizeof ( type-id )
    +typeid ( expression )
    +typeid ( type-id )
    +alignof ( type-id )
    +noexcept ( expression )

    A reflect-expression is value-dependent if the operand of the reflection operator is a @@ -7000,8 +6846,8 @@

    15.2 9 Preprocessing directives of the forms

    -
         # if      constant-expression new-line groupopt
    -     # elif    constant-expression new-line groupopt
    +
         # if      constant-expression new-line groupopt
    +     # elif    constant-expression new-line groupopt

    check whether the controlling constant expression evaluates to nonzero. The program is ill-formed if a splice-specifier or @@ -7074,20 +6920,20 @@

    21 synopsis

    -
        // [meta.unary.cat], primary type categories
    -    template<class T> struct is_void;
    -...
    -    template<class T> struct is_function;
    -+   template<class T> struct is_reflection;
    -
    -    // [meta.unary.cat], primary type categories
    -    template<class T>
    -      constexpr bool is_void_v = is_void<T>::value;
    -...
    -    template<class T>
    -      constexpr bool is_function_v = is_function<T>::value;
    -+   template<class T>
    -+     constexpr bool is_reflection_v = is_reflection<T>::value;
    +
        // [meta.unary.cat], primary type categories
    +    template<class T> struct is_void;
    +...
    +    template<class T> struct is_function;
    ++   template<class T> struct is_reflection;
    +
    +    // [meta.unary.cat], primary type categories
    +    template<class T>
    +      constexpr bool is_void_v = is_void<T>::value;
    +...
    +    template<class T>
    +      constexpr bool is_function_v = is_function<T>::value;
    ++   template<class T>
    ++     constexpr bool is_reflection_v = is_reflection<T>::value;
    @@ -7109,8 +6955,8 @@

    21.3.5. -
    template <class T>
    -struct is_void;
    +
    template <class T>
    +struct is_void;
    T is @@ -7133,8 +6979,8 @@

    21.3.5.
    -
    template <class T>
    -struct is_reflection;
    +
    template <class T>
    +struct is_reflection;
    @@ -7158,359 +7004,354 @@

    [meta.synop]

    Header <meta> synopsis

    -
    #include <initializer_list>
    -#include <ranges>
    -#include <string_view>
    -#include <vector>
    -
    -namespace std::meta {
    -  using info = decltype(^::);
    -
    -  // [meta.reflection.operators], operator representations
    -  enum class operators {
    -    see below;
    -  };
    -  using enum operators;
    -  consteval operators operator_of(info r);
    -  consteval string_view symbol_of(operators op);
    -  consteval u8string_view u8symbol_of(operators op);
    -
    -  // [meta.reflection.names], reflection names and locations
    -  consteval bool has_identifier(info r);
    -
    -  consteval string_view identifier_of(info r);
    -  consteval string_view u8identifier_of(info r);
    -
    -  consteval string_view display_string_of(info r);
    -  consteval string_view u8display_string_of(info r);
    -
    -  consteval source_location source_location_of(info r);
    -
    -  // [meta.reflection.queries], reflection queries
    -  consteval bool is_public(info r);
    -  consteval bool is_protected(info r);
    -  consteval bool is_private(info r);
    -
    -  consteval bool is_virtual(info r);
    -  consteval bool is_pure_virtual(info r);
    -  consteval bool is_override(info r);
    -  consteval bool is_final(info r);
    -
    -  consteval bool is_deleted(info r);
    -  consteval bool is_defaulted(info r);
    -  consteval bool is_user_provided(info r);
    -  consteval bool is_user_declared(info r);
    -  consteval bool is_explicit(info r);
    -  consteval bool is_noexcept(info r);
    -
    -  consteval bool is_bit_field(info r);
    -  consteval bool is_enumerator(info r);
    -
    -  consteval bool is_const(info r);
    -  consteval bool is_volatile(info r);
    -  consteval bool is_mutable_member(info r);
    -  consteval bool is_lvalue_reference_qualified(info r);
    -  consteval bool is_rvalue_reference_qualified(info r);
    -
    -  consteval bool has_static_storage_duration(info r);
    -  consteval bool has_thread_storage_duration(info r);
    -  consteval bool has_automatic_storage_duration(info r);
    -
    -  consteval bool has_internal_linkage(info r);
    -  consteval bool has_module_linkage(info r);
    -  consteval bool has_external_linkage(info r);
    -  consteval bool has_linkage(info r);
    -
    -  consteval bool is_complete_type(info r);
    -  consteval bool has_complete_definition(info r);
    -
    -  consteval bool is_namespace(info r);
    -  consteval bool is_variable(info r);
    -  consteval bool is_type(info r);
    -  consteval bool is_type_alias(info r);
    -  consteval bool is_namespace_alias(info r);
    -
    -  consteval bool is_function(info r);
    -  consteval bool is_conversion_function(info r);
    -  consteval bool is_operator_function(info r);
    -  consteval bool is_literal_operator(info r);
    -  consteval bool is_special_member_function(info r);
    -  consteval bool is_constructor(info r);
    -  consteval bool is_default_constructor(info r);
    -  consteval bool is_copy_constructor(info r);
    -  consteval bool is_move_constructor(info r);
    -  consteval bool is_assignment(info r);
    -  consteval bool is_copy_assignment(info r);
    -  consteval bool is_move_assignment(info r);
    -  consteval bool is_destructor(info r);
    -
    -  consteval bool is_template(info r);
    -  consteval bool is_function_template(info r);
    -  consteval bool is_variable_template(info r);
    -  consteval bool is_class_template(info r);
    -  consteval bool is_alias_template(info r);
    -  consteval bool is_conversion_function_template(info r);
    -  consteval bool is_operator_function_template(info r);
    -  consteval bool is_literal_operator_template(info r);
    -  consteval bool is_constructor_template(info r);
    -  consteval bool is_concept(info r);
    -  consteval bool has_template_arguments(info r);
    -
    -  consteval bool is_value(info r);
    -  consteval bool is_object(info r);
    -
    -  consteval bool is_structured_binding(info r);
    -
    -  consteval bool is_class_member(info r);
    -  consteval bool is_namespace_member(info r);
    -  consteval bool is_nonstatic_data_member(info r);
    -  consteval bool is_static_member(info r);
    -  consteval bool is_base(info r);
    -
    -  consteval bool has_default_member_initializer(info r);
    -
    -  consteval info type_of(info r);
    -  consteval info object_of(info r);
    -  consteval info value_of(info r);
    -  consteval info parent_of(info r);
    -  consteval info dealias(info r);
    -  consteval info template_of(info r);
    -  consteval vector<info> template_arguments_of(info r);
    -
    -  // [meta.reflection.member.queries], reflection member queries
    -  consteval vector<info> members_of(info r);
    -  consteval vector<info> bases_of(info type);
    -  consteval vector<info> static_data_members_of(info type);
    -  consteval vector<info> nonstatic_data_members_of(info type);
    -  consteval vector<info> enumerators_of(info type_enum);
    -
    -  consteval vector<info> get_public_members(info type);
    -  consteval vector<info> get_public_static_data_members(info type);
    -  consteval vector<info> get_public_nonstatic_data_members(info type);
    -  consteval vector<info> get_public_bases(info type);
    -
    -  // [meta.reflection.layout], reflection layout queries
    -  struct member_offset {
    -    ptrdiff_t bytes;
    -    ptrdiff_t bits;
    -    constexpr ptrdiff_t total_bits() const;
    -    auto operator<=>(member_offset const&) const = default;
    -  };
    -  consteval member_offset offset_of(info r);
    -  consteval size_t size_of(info r);
    -  consteval size_t alignment_of(info r);
    -  consteval size_t bit_size_of(info r);
    -
    -  // [meta.reflection.extract], value extraction
    -  template<class T>
    -    consteval T extract(info);
    -
    -  // [meta.reflection.substitute], reflection substitution
    -  template <class R>
    -    concept reflection_range = see below;
    -
    -  template <reflection_range R = initializer_list<info>>
    -    consteval bool can_substitute(info templ, R&& arguments);
    -  template <reflection_range R = initializer_list<info>>
    -    consteval info substitute(info templ, R&& arguments);
    -
    -  // [meta.reflection.result], expression result reflection
    -  template<class T>
    -    consteval info reflect_value(T value);
    -  template<class T>
    -    consteval info reflect_object(T& object);
    -  template<class T>
    -    consteval info reflect_function(T& fn);
    -
    -  template <reflection_range R = initializer_list<info>>
    -    consteval info reflect_invoke(info target, R&& args);
    -  template <reflection_range R1 = initializer_list<info>, reflection_range R2 = initializer_list<info>>
    -    consteval info reflect_invoke(info target, R1&& tmpl_args, R2&& args);
    -
    -  // [meta.reflection.define_class], class definition generation
    -  struct data_member_options_t {
    -    struct name_type {
    -      template<class T> requires constructible_from<u8string, T>
    -        consteval name_type(T &&);
    -
    -      template<class T> requires constructible_from<string, T>
    -        consteval name_type(T &&);
    -
    -      variant<u8string, string> contents;    // exposition only
    -    };
    -
    -    optional<name_type> name;
    -    optional<int> alignment;
    -    optional<int> width;
    -    bool no_unique_address = false;
    -  };
    -  consteval info data_member_spec(info type,
    -                                  data_member_options_t options = {});
    -  consteval bool is_data_member_spec(info r);
    -  template <reflection_range R = initializer_list<info>>
    -  consteval info define_class(info type_class, R&&);
    -
    -  // [meta.reflection.unary.cat], primary type categories
    -  consteval bool type_is_void(info type);
    -  consteval bool type_is_null_pointer(info type);
    -  consteval bool type_is_integral(info type);
    -  consteval bool type_is_floating_point(info type);
    -  consteval bool type_is_array(info type);
    -  consteval bool type_is_pointer(info type);
    -  consteval bool type_is_lvalue_reference(info type);
    -  consteval bool type_is_rvalue_reference(info type);
    -  consteval bool type_is_member_object_pointer(info type);
    -  consteval bool type_is_member_function_pointer(info type);
    -  consteval bool type_is_enum(info type);
    -  consteval bool type_is_union(info type);
    -  consteval bool type_is_class(info type);
    -  consteval bool type_is_function(info type);
    -  consteval bool type_is_reflection(info type);
    -
    -  // [meta.reflection.unary.comp], composite type categories
    -  consteval bool type_is_reference(info type);
    -  consteval bool type_is_arithmetic(info type);
    -  consteval bool type_is_fundamental(info type);
    -  consteval bool type_is_object(info type);
    -  consteval bool type_is_scalar(info type);
    -  consteval bool type_is_compound(info type);
    -  consteval bool type_is_member_pointer(info type);
    -
    -  // [meta.reflection unary.prop], type properties
    -  consteval bool type_is_const(info type);
    -  consteval bool type_is_volatile(info type);
    -  consteval bool type_is_trivial(info type);
    -  consteval bool type_is_trivially_copyable(info type);
    -  consteval bool type_is_standard_layout(info type);
    -  consteval bool type_is_empty(info type);
    -  consteval bool type_is_polymorphic(info type);
    -  consteval bool type_is_abstract(info type);
    -  consteval bool type_is_final(info type);
    -  consteval bool type_is_aggregate(info type);
    -  consteval bool type_is_signed(info type);
    -  consteval bool type_is_unsigned(info type);
    -  consteval bool type_is_bounded_array(info type);
    -  consteval bool type_is_unbounded_array(info type);
    -  consteval bool type_is_scoped_enum(info type);
    -
    -  template <reflection_range R = initializer_list<info>>
    -    consteval bool type_is_constructible(info type, R&& type_args);
    -  consteval bool type_is_default_constructible(info type);
    -  consteval bool type_is_copy_constructible(info type);
    -  consteval bool type_is_move_constructible(info type);
    -
    -  consteval bool type_is_assignable(info type_dst, info type_src);
    -  consteval bool type_is_copy_assignable(info type);
    -  consteval bool type_is_move_assignable(info type);
    -
    -  consteval bool type_is_swappable_with(info type_dst, info type_src);
    -  consteval bool type_is_swappable(info type);
    -
    -  consteval bool type_is_destructible(info type);
    -
    -  template <reflection_range R = initializer_list<info>>
    -    consteval bool type_is_trivially_constructible(info type, R&& type_args);
    -  consteval bool type_is_trivially_default_constructible(info type);
    -  consteval bool type_is_trivially_copy_constructible(info type);
    -  consteval bool type_is_trivially_move_constructible(info type);
    -
    -  consteval bool type_is_trivially_assignable(info type_dst, info type_src);
    -  consteval bool type_is_trivially_copy_assignable(info type);
    -  consteval bool type_is_trivially_move_assignable(info type);
    -  consteval bool type_is_trivially_destructible(info type);
    -
    -  template <reflection_range R = initializer_list<info>>
    -    consteval bool type_is_nothrow_constructible(info type, R&& type_args);
    -  consteval bool type_is_nothrow_default_constructible(info type);
    -  consteval bool type_is_nothrow_copy_constructible(info type);
    -  consteval bool type_is_nothrow_move_constructible(info type);
    -
    -  consteval bool type_is_nothrow_assignable(info type_dst, info type_src);
    -  consteval bool type_is_nothrow_copy_assignable(info type);
    -  consteval bool type_is_nothrow_move_assignable(info type);
    -
    -  consteval bool type_is_nothrow_swappable_with(info type_dst, info type_src);
    -  consteval bool type_is_nothrow_swappable(info type);
    -
    -  consteval bool type_is_nothrow_destructible(info type);
    -
    -  consteval bool type_is_implicit_lifetime(info type);
    -
    -  consteval bool type_has_virtual_destructor(info type);
    -
    -  consteval bool type_has_unique_object_representations(info type);
    -
    -  consteval bool type_reference_constructs_from_temporary(info type_dst, info type_src);
    -  consteval bool type_reference_converts_from_temporary(info type_dst, info type_src);
    -
    -  // [meta.reflection.unary.prop.query], type property queries
    -  consteval size_t type_alignment_of(info type);
    -  consteval size_t type_rank(info type);
    -  consteval size_t type_extent(info type, unsigned i = 0);
    -
    -  // [meta.reflection.rel], type relations
    -  consteval bool type_is_same(info type1, info type2);
    -  consteval bool type_is_base_of(info type_base, info type_derived);
    -  consteval bool type_is_convertible(info type_src, info type_dst);
    -  consteval bool type_is_nothrow_convertible(info type_src, info type_dst);
    -  consteval bool type_is_layout_compatible(info type1, info type2);
    -  consteval bool type_is_pointer_interconvertible_base_of(info type_base, info type_derived);
    -
    -  template <reflection_range R = initializer_list<info>>
    -    consteval bool type_is_invocable(info type, R&& type_args);
    -  template <reflection_range R = initializer_list<info>>
    -    consteval bool type_is_invocable_r(info type_result, info type, R&& type_args);
    -
    -  template <reflection_range R = initializer_list<info>>
    -    consteval bool type_is_nothrow_invocable(info type, R&& type_args);
    -  template <reflection_range R = initializer_list<info>>
    -    consteval bool type_is_nothrow_invocable_r(info type_result, info type, R&& type_args);
    -
    -  // [meta.reflection.trans.cv], const-volatile modifications
    -  consteval info type_remove_const(info type);
    -  consteval info type_remove_volatile(info type);
    -  consteval info type_remove_cv(info type);
    -  consteval info type_add_const(info type);
    -  consteval info type_add_volatile(info type);
    -  consteval info type_add_cv(info type);
    -
    -  // [meta.reflection.trans.ref], reference modifications
    -  consteval info type_remove_reference(info type);
    -  consteval info type_add_lvalue_reference(info type);
    -  consteval info type_add_rvalue_reference(info type);
    -
    -  // [meta.reflection.trans.sign], sign modifications
    -  consteval info type_make_signed(info type);
    -  consteval info type_make_unsigned(info type);
    -
    -  // [meta.reflection.trans.arr], array modifications
    -  consteval info type_remove_extent(info type);
    -  consteval info type_remove_all_extents(info type);
    -
    -  // [meta.reflection.trans.ptr], pointer modifications
    -  consteval info type_remove_pointer(info type);
    -  consteval info type_add_pointer(info type);
    -
    -  // [meta.reflection.trans.other], other transformations
    -  consteval info type_remove_cvref(info type);
    -  consteval info type_decay(info type);
    -  template <reflection_range R = initializer_list<info>>
    -    consteval info type_common_type(R&& type_args);
    -  template <reflection_range R = initializer_list<info>>
    -    consteval info type_common_reference(R&& type_args);
    -  consteval info type_underlying_type(info type);
    -  template <reflection_range R = initializer_list<info>>
    -    `consteval info type_invoke_result(info type, R&& type_args);
    -  consteval info type_unwrap_reference(info type);
    -  consteval info type_unwrap_ref_decay(info type);
    -
    -  // [meta.reflection.tuple.variant], tuple and variant queries
    -  consteval size_t type_tuple_size(info type);
    -  consteval info type_tuple_element(size_t index, info type);
    -
    -  consteval size_t type_variant_size(info type);
    -  consteval info type_variant_alternative(size_t index, info type);
    -}
    +
    #include <initializer_list>
    +#include <ranges>
    +#include <string_view>
    +#include <vector>
    +
    +namespace std::meta {
    +  using info = decltype(^::);
    +
    +  // [meta.reflection.operators], operator representations
    +  enum class operators {
    +    see below;
    +  };
    +  using enum operators;
    +  consteval operators operator_of(info r);
    +  consteval string_view symbol_of(operators op);
    +  consteval u8string_view u8symbol_of(operators op);
    +
    +  // [meta.reflection.names], reflection names and locations
    +  consteval bool has_identifier(info r);
    +
    +  consteval string_view identifier_of(info r);
    +  consteval string_view u8identifier_of(info r);
    +
    +  consteval string_view display_string_of(info r);
    +  consteval string_view u8display_string_of(info r);
    +
    +  consteval source_location source_location_of(info r);
    +
    +  // [meta.reflection.queries], reflection queries
    +  consteval bool is_public(info r);
    +  consteval bool is_protected(info r);
    +  consteval bool is_private(info r);
    +
    +  consteval bool is_virtual(info r);
    +  consteval bool is_pure_virtual(info r);
    +  consteval bool is_override(info r);
    +  consteval bool is_final(info r);
    +
    +  consteval bool is_deleted(info r);
    +  consteval bool is_defaulted(info r);
    +  consteval bool is_user_provided(info r);
    +  consteval bool is_user_declared(info r);
    +  consteval bool is_explicit(info r);
    +  consteval bool is_noexcept(info r);
    +
    +  consteval bool is_bit_field(info r);
    +  consteval bool is_enumerator(info r);
    +
    +  consteval bool is_const(info r);
    +  consteval bool is_volatile(info r);
    +  consteval bool is_mutable_member(info r);
    +  consteval bool is_lvalue_reference_qualified(info r);
    +  consteval bool is_rvalue_reference_qualified(info r);
    +
    +  consteval bool has_static_storage_duration(info r);
    +  consteval bool has_thread_storage_duration(info r);
    +  consteval bool has_automatic_storage_duration(info r);
    +
    +  consteval bool has_internal_linkage(info r);
    +  consteval bool has_module_linkage(info r);
    +  consteval bool has_external_linkage(info r);
    +  consteval bool has_linkage(info r);
    +
    +  consteval bool is_complete_type(info r);
    +  consteval bool has_complete_definition(info r);
    +
    +  consteval bool is_namespace(info r);
    +  consteval bool is_variable(info r);
    +  consteval bool is_type(info r);
    +  consteval bool is_type_alias(info r);
    +  consteval bool is_namespace_alias(info r);
    +
    +  consteval bool is_function(info r);
    +  consteval bool is_conversion_function(info r);
    +  consteval bool is_operator_function(info r);
    +  consteval bool is_literal_operator(info r);
    +  consteval bool is_special_member_function(info r);
    +  consteval bool is_constructor(info r);
    +  consteval bool is_default_constructor(info r);
    +  consteval bool is_copy_constructor(info r);
    +  consteval bool is_move_constructor(info r);
    +  consteval bool is_assignment(info r);
    +  consteval bool is_copy_assignment(info r);
    +  consteval bool is_move_assignment(info r);
    +  consteval bool is_destructor(info r);
    +
    +  consteval bool is_template(info r);
    +  consteval bool is_function_template(info r);
    +  consteval bool is_variable_template(info r);
    +  consteval bool is_class_template(info r);
    +  consteval bool is_alias_template(info r);
    +  consteval bool is_conversion_function_template(info r);
    +  consteval bool is_operator_function_template(info r);
    +  consteval bool is_literal_operator_template(info r);
    +  consteval bool is_constructor_template(info r);
    +  consteval bool is_concept(info r);
    +  consteval bool has_template_arguments(info r);
    +
    +  consteval bool is_value(info r);
    +  consteval bool is_object(info r);
    +
    +  consteval bool is_structured_binding(info r);
    +
    +  consteval bool is_class_member(info r);
    +  consteval bool is_namespace_member(info r);
    +  consteval bool is_nonstatic_data_member(info r);
    +  consteval bool is_static_member(info r);
    +  consteval bool is_base(info r);
    +
    +  consteval bool has_default_member_initializer(info r);
    +
    +  consteval info type_of(info r);
    +  consteval info object_of(info r);
    +  consteval info value_of(info r);
    +  consteval info parent_of(info r);
    +  consteval info dealias(info r);
    +  consteval info template_of(info r);
    +  consteval vector<info> template_arguments_of(info r);
    +
    +  // [meta.reflection.member.queries], reflection member queries
    +  consteval vector<info> members_of(info r);
    +  consteval vector<info> bases_of(info type);
    +  consteval vector<info> static_data_members_of(info type);
    +  consteval vector<info> nonstatic_data_members_of(info type);
    +  consteval vector<info> enumerators_of(info type_enum);
    +
    +  consteval vector<info> get_public_members(info type);
    +  consteval vector<info> get_public_static_data_members(info type);
    +  consteval vector<info> get_public_nonstatic_data_members(info type);
    +  consteval vector<info> get_public_bases(info type);
    +
    +  // [meta.reflection.layout], reflection layout queries
    +  struct member_offset {
    +    ptrdiff_t bytes;
    +    ptrdiff_t bits;
    +    constexpr ptrdiff_t total_bits() const;
    +    auto operator<=>(member_offset const&) const = default;
    +  };
    +  consteval member_offset offset_of(info r);
    +  consteval size_t size_of(info r);
    +  consteval size_t alignment_of(info r);
    +  consteval size_t bit_size_of(info r);
    +
    +  // [meta.reflection.extract], value extraction
    +  template<class T>
    +    consteval T extract(info);
    +
    +  // [meta.reflection.substitute], reflection substitution
    +  template <class R>
    +    concept reflection_range = see below;
    +
    +  template <reflection_range R = initializer_list<info>>
    +    consteval bool can_substitute(info templ, R&& arguments);
    +  template <reflection_range R = initializer_list<info>>
    +    consteval info substitute(info templ, R&& arguments);
    +
    +  // [meta.reflection.result], expression result reflection
    +  template<class T>
    +    consteval info reflect_value(T value);
    +  template<class T>
    +    consteval info reflect_object(T& object);
    +  template<class T>
    +    consteval info reflect_function(T& fn);
    +
    +  // [meta.reflection.define_class], class definition generation
    +  struct data_member_options_t {
    +    struct name_type {
    +      template<class T> requires constructible_from<u8string, T>
    +        consteval name_type(T &&);
    +
    +      template<class T> requires constructible_from<string, T>
    +        consteval name_type(T &&);
    +
    +      variant<u8string, string> contents;    // exposition only
    +    };
    +
    +    optional<name_type> name;
    +    optional<int> alignment;
    +    optional<int> width;
    +    bool no_unique_address = false;
    +  };
    +  consteval info data_member_spec(info type,
    +                                  data_member_options_t options = {});
    +  consteval bool is_data_member_spec(info r);
    +  template <reflection_range R = initializer_list<info>>
    +  consteval info define_class(info type_class, R&&);
    +
    +  // [meta.reflection.unary.cat], primary type categories
    +  consteval bool type_is_void(info type);
    +  consteval bool type_is_null_pointer(info type);
    +  consteval bool type_is_integral(info type);
    +  consteval bool type_is_floating_point(info type);
    +  consteval bool type_is_array(info type);
    +  consteval bool type_is_pointer(info type);
    +  consteval bool type_is_lvalue_reference(info type);
    +  consteval bool type_is_rvalue_reference(info type);
    +  consteval bool type_is_member_object_pointer(info type);
    +  consteval bool type_is_member_function_pointer(info type);
    +  consteval bool type_is_enum(info type);
    +  consteval bool type_is_union(info type);
    +  consteval bool type_is_class(info type);
    +  consteval bool type_is_function(info type);
    +  consteval bool type_is_reflection(info type);
    +
    +  // [meta.reflection.unary.comp], composite type categories
    +  consteval bool type_is_reference(info type);
    +  consteval bool type_is_arithmetic(info type);
    +  consteval bool type_is_fundamental(info type);
    +  consteval bool type_is_object(info type);
    +  consteval bool type_is_scalar(info type);
    +  consteval bool type_is_compound(info type);
    +  consteval bool type_is_member_pointer(info type);
    +
    +  // [meta.reflection unary.prop], type properties
    +  consteval bool type_is_const(info type);
    +  consteval bool type_is_volatile(info type);
    +  consteval bool type_is_trivial(info type);
    +  consteval bool type_is_trivially_copyable(info type);
    +  consteval bool type_is_standard_layout(info type);
    +  consteval bool type_is_empty(info type);
    +  consteval bool type_is_polymorphic(info type);
    +  consteval bool type_is_abstract(info type);
    +  consteval bool type_is_final(info type);
    +  consteval bool type_is_aggregate(info type);
    +  consteval bool type_is_signed(info type);
    +  consteval bool type_is_unsigned(info type);
    +  consteval bool type_is_bounded_array(info type);
    +  consteval bool type_is_unbounded_array(info type);
    +  consteval bool type_is_scoped_enum(info type);
    +
    +  template <reflection_range R = initializer_list<info>>
    +    consteval bool type_is_constructible(info type, R&& type_args);
    +  consteval bool type_is_default_constructible(info type);
    +  consteval bool type_is_copy_constructible(info type);
    +  consteval bool type_is_move_constructible(info type);
    +
    +  consteval bool type_is_assignable(info type_dst, info type_src);
    +  consteval bool type_is_copy_assignable(info type);
    +  consteval bool type_is_move_assignable(info type);
    +
    +  consteval bool type_is_swappable_with(info type_dst, info type_src);
    +  consteval bool type_is_swappable(info type);
    +
    +  consteval bool type_is_destructible(info type);
    +
    +  template <reflection_range R = initializer_list<info>>
    +    consteval bool type_is_trivially_constructible(info type, R&& type_args);
    +  consteval bool type_is_trivially_default_constructible(info type);
    +  consteval bool type_is_trivially_copy_constructible(info type);
    +  consteval bool type_is_trivially_move_constructible(info type);
    +
    +  consteval bool type_is_trivially_assignable(info type_dst, info type_src);
    +  consteval bool type_is_trivially_copy_assignable(info type);
    +  consteval bool type_is_trivially_move_assignable(info type);
    +  consteval bool type_is_trivially_destructible(info type);
    +
    +  template <reflection_range R = initializer_list<info>>
    +    consteval bool type_is_nothrow_constructible(info type, R&& type_args);
    +  consteval bool type_is_nothrow_default_constructible(info type);
    +  consteval bool type_is_nothrow_copy_constructible(info type);
    +  consteval bool type_is_nothrow_move_constructible(info type);
    +
    +  consteval bool type_is_nothrow_assignable(info type_dst, info type_src);
    +  consteval bool type_is_nothrow_copy_assignable(info type);
    +  consteval bool type_is_nothrow_move_assignable(info type);
    +
    +  consteval bool type_is_nothrow_swappable_with(info type_dst, info type_src);
    +  consteval bool type_is_nothrow_swappable(info type);
    +
    +  consteval bool type_is_nothrow_destructible(info type);
    +
    +  consteval bool type_is_implicit_lifetime(info type);
    +
    +  consteval bool type_has_virtual_destructor(info type);
    +
    +  consteval bool type_has_unique_object_representations(info type);
    +
    +  consteval bool type_reference_constructs_from_temporary(info type_dst, info type_src);
    +  consteval bool type_reference_converts_from_temporary(info type_dst, info type_src);
    +
    +  // [meta.reflection.unary.prop.query], type property queries
    +  consteval size_t type_alignment_of(info type);
    +  consteval size_t type_rank(info type);
    +  consteval size_t type_extent(info type, unsigned i = 0);
    +
    +  // [meta.reflection.rel], type relations
    +  consteval bool type_is_same(info type1, info type2);
    +  consteval bool type_is_base_of(info type_base, info type_derived);
    +  consteval bool type_is_convertible(info type_src, info type_dst);
    +  consteval bool type_is_nothrow_convertible(info type_src, info type_dst);
    +  consteval bool type_is_layout_compatible(info type1, info type2);
    +  consteval bool type_is_pointer_interconvertible_base_of(info type_base, info type_derived);
    +
    +  template <reflection_range R = initializer_list<info>>
    +    consteval bool type_is_invocable(info type, R&& type_args);
    +  template <reflection_range R = initializer_list<info>>
    +    consteval bool type_is_invocable_r(info type_result, info type, R&& type_args);
    +
    +  template <reflection_range R = initializer_list<info>>
    +    consteval bool type_is_nothrow_invocable(info type, R&& type_args);
    +  template <reflection_range R = initializer_list<info>>
    +    consteval bool type_is_nothrow_invocable_r(info type_result, info type, R&& type_args);
    +
    +  // [meta.reflection.trans.cv], const-volatile modifications
    +  consteval info type_remove_const(info type);
    +  consteval info type_remove_volatile(info type);
    +  consteval info type_remove_cv(info type);
    +  consteval info type_add_const(info type);
    +  consteval info type_add_volatile(info type);
    +  consteval info type_add_cv(info type);
    +
    +  // [meta.reflection.trans.ref], reference modifications
    +  consteval info type_remove_reference(info type);
    +  consteval info type_add_lvalue_reference(info type);
    +  consteval info type_add_rvalue_reference(info type);
    +
    +  // [meta.reflection.trans.sign], sign modifications
    +  consteval info type_make_signed(info type);
    +  consteval info type_make_unsigned(info type);
    +
    +  // [meta.reflection.trans.arr], array modifications
    +  consteval info type_remove_extent(info type);
    +  consteval info type_remove_all_extents(info type);
    +
    +  // [meta.reflection.trans.ptr], pointer modifications
    +  consteval info type_remove_pointer(info type);
    +  consteval info type_add_pointer(info type);
    +
    +  // [meta.reflection.trans.other], other transformations
    +  consteval info type_remove_cvref(info type);
    +  consteval info type_decay(info type);
    +  template <reflection_range R = initializer_list<info>>
    +    consteval info type_common_type(R&& type_args);
    +  template <reflection_range R = initializer_list<info>>
    +    consteval info type_common_reference(R&& type_args);
    +  consteval info type_underlying_type(info type);
    +  template <reflection_range R = initializer_list<info>>
    +    `consteval info type_invoke_result(info type, R&& type_args);
    +  consteval info type_unwrap_reference(info type);
    +  consteval info type_unwrap_ref_decay(info type);
    +
    +  // [meta.reflection.tuple.variant], tuple and variant queries
    +  consteval size_t type_tuple_size(info type);
    +  consteval info type_tuple_element(size_t index, info type);
    +
    +  consteval size_t type_variant_size(info type);
    +  consteval info type_variant_alternative(size_t index, info type);
    +}

    1 Each function, and each instantiation of each function template, specified in this header is a designated addressable function @@ -7523,10 +7364,10 @@

    [
    -
    enum class operators {
    -  see below;
    -};
    -using enum operators;
    +
    enum class operators {
    +  see below;
    +};
    +using enum operators;

    1 This enum class specifies constants used to identify operators that can be overloaded, with the meanings listed in Table 1. The values of the @@ -7779,7 +7620,7 @@

    [ -
    consteval operators operator_of(info r);
    +
    consteval operators operator_of(info r);

    2 Constant When: r represents an operator function or operator function template.

    @@ -7789,8 +7630,8 @@

    [ operator-function-id is the unqualified name of the entity represented by r.

    -
    consteval string_view symbol_of(operators op);
    -consteval u8string_view u8symbol_of(operators op);
    +
    consteval string_view symbol_of(operators op);
    +consteval u8string_view u8symbol_of(operators op);

    4 Constant When: The value of op corresponds to one of the @@ -7809,7 +7650,7 @@

    -
    consteval bool has_identifier(info r);
    +
    consteval bool has_identifier(info r);

    1 Returns:

      @@ -7874,8 +7715,8 @@

      false.

    -
    consteval string_view identifier_of(info r);
    -consteval u8string_view u8identifier_of(info r);
    +
    consteval string_view identifier_of(info r);
    +consteval u8string_view u8identifier_of(info r);

    2 Let E be UTF-8 if returning a u8string_view, and otherwise the @@ -7916,8 +7757,8 @@

    u8string contents of o.name.contents encoded with E.

  • -
    consteval string_view display_string_of(info r);
    -consteval u8string_view u8display_string_of(info r);
    +
    consteval string_view display_string_of(info r);
    +consteval u8string_view u8display_string_of(info r);

    5 Returns: An implementation-defined string_view or @@ -7925,7 +7766,7 @@

    6 Recommended practice: Where possible, implementations should return a string suitable for identifying the represented construct.

    -
    consteval source_location source_location_of(info r);
    +
    consteval source_location source_location_of(info r);

    7 Returns: If r represents a value, a non-class type, the global namespace, or a description of a @@ -7947,9 +7788,9 @@

    [meta.ref
    -
    consteval bool is_public(info r);
    -consteval bool is_protected(info r);
    -consteval bool is_private(info r);
    +
    consteval bool is_public(info r);
    +consteval bool is_protected(info r);
    +consteval bool is_private(info r);

    1 Returns: true if @@ -7957,15 +7798,15 @@

    [meta.ref class specifier that is public, protected, or private, respectively. Otherwise, false.

    -
    consteval bool is_virtual(info r);
    +
    consteval bool is_virtual(info r);

    2 Returns: true if r represents either a virtual member function or a virtual base class specifier. Otherwise, false.

    -
    consteval bool is_pure_virtual(info r);
    -consteval bool is_override(info r);
    +
    consteval bool is_pure_virtual(info r);
    +consteval bool is_override(info r);

    3 Returns: true if @@ -7973,15 +7814,15 @@

    [meta.ref is pure virtual or overrides another member function, respectively. Otherwise, false.

    -
    consteval bool is_final(info r);
    +
    consteval bool is_final(info r);

    4 Returns: true if r represents a final class or a final member function. Otherwise, false.

    -
    consteval bool is_deleted(info r);
    -consteval bool is_defaulted(info r);
    +
    consteval bool is_deleted(info r);
    +consteval bool is_defaulted(info r);

    5 Returns: true if @@ -7989,8 +7830,8 @@

    [meta.ref defined as deleted ([dcl.fct.def.delete])or defined as defaulted ([dcl.fct.def.default]), respectively. Otherwise, false.

    -
    consteval bool is_user_provided(info r);
    -consteval bool is_user_declared(info r);
    +
    consteval bool is_user_provided(info r);
    +consteval bool is_user_declared(info r);

    6 Returns: true if @@ -7998,7 +7839,7 @@

    [meta.ref user-provided or user-declared (9.5.2 [dcl.fct.def.default]), respectively. Otherwise, false.

    -
    consteval bool is_explicit(info r);
    +
    consteval bool is_explicit(info r);

    7 Returns: true if @@ -8013,7 +7854,7 @@

    [meta.ref false because in general such queries for templates cannot be answered. — end note ]

    -
    consteval bool is_noexcept(info r);
    +
    consteval bool is_noexcept(info r);

    8 Returns: true if @@ -8031,7 +7872,7 @@

    [meta.ref false because in general such queries for templates cannot be answered. — end note ]

    -
    consteval bool is_bit_field(info r);
    +
    consteval bool is_bit_field(info r);

    9 Returns: true if @@ -8041,15 +7882,15 @@

    [meta.ref declared with the properties represented by r would be a bit-field. Otherwise, false.

    -
    consteval bool is_enumerator(info r);
    +
    consteval bool is_enumerator(info r);

    10 Returns: true if r represents an enumerator. Otherwise, false.

    -
    consteval bool is_const(info r);
    -consteval bool is_volatile(info r);
    +
    consteval bool is_const(info r);
    +consteval bool is_volatile(info r);

    11 Returns: true if @@ -8058,7 +7899,7 @@

    [meta.ref (respectively), or an object, variable, non-static data member, or function with such a type. Otherwise, false.

    -
    consteval bool is_mutable_member(info r);
    +
    consteval bool is_mutable_member(info r);

    12 Returns: true if @@ -8066,8 +7907,8 @@

    [meta.ref mutable non-static data member. Otherwise, false.

    -
    consteval bool is_lvalue_reference_qualified(info r);
    -consteval bool is_rvalue_reference_qualified(info r);
    +
    consteval bool is_lvalue_reference_qualified(info r);
    +consteval bool is_rvalue_reference_qualified(info r);

    13 Returns: true if @@ -8075,9 +7916,9 @@

    [meta.ref rvalue-reference qualified function type (respectively), or a member function with such a type. Otherwise, false.

    -
    consteval bool has_static_storage_duration(info r);
    -consteval bool has_thread_storage_duration(info r);
    -consteval bool has_automatic_storage_duration(info r);
    +
    consteval bool has_static_storage_duration(info r);
    +consteval bool has_thread_storage_duration(info r);
    +consteval bool has_automatic_storage_duration(info r);

    14 Returns: true if @@ -8085,10 +7926,10 @@

    [meta.ref that has static, thread, or automatic storage duration, respectively ([basic.stc]). Otherwise, false.

    -
    consteval bool has_internal_linkage(info r);
    -consteval bool has_module_linkage(info r);
    -consteval bool has_external_linkage(info r);
    -consteval bool has_linkage(info r);
    +
    consteval bool has_internal_linkage(info r);
    +consteval bool has_module_linkage(info r);
    +consteval bool has_external_linkage(info r);
    +consteval bool has_linkage(info r);

    15 Returns: true if @@ -8097,7 +7938,7 @@

    [meta.ref linkage, external linkage, or any linkage, respectively ([basic.link]). Otherwise, false.

    -
    consteval bool is_complete_type(info r);
    +
    consteval bool is_complete_type(info r);

    16 Effects: If is_type(r) is true and @@ -8113,7 +7954,7 @@

    [meta.ref represented by dealias(r) is not an incomplete type ([basic.types]). Otherwise, false.

    -
    consteval bool has_complete_definition(info r);
    +
    consteval bool has_complete_definition(info r);

    18 Effects: If is_type(r) is true and @@ -8128,28 +7969,28 @@

    [meta.ref that no entities not already declared may be introduced within the scope of E. Otherwise false.

    -
    consteval bool is_namespace(info r);
    +
    consteval bool is_namespace(info r);

    20 Returns: true if r represents a namespace or namespace alias. Otherwise, false.

    -
    consteval bool is_variable(info r);
    +
    consteval bool is_variable(info r);

    21 Returns: true if r represents a variable. Otherwise, false.

    -
    consteval bool is_type(info r);
    +
    consteval bool is_type(info r);

    22 Returns: true if r represents a type or a typedef-name. Otherwise, false.

    -
    consteval bool is_type_alias(info r);
    -consteval bool is_namespace_alias(info r);
    +
    consteval bool is_type_alias(info r);
    +consteval bool is_namespace_alias(info r);

    23 Returns: true if @@ -8160,30 +8001,30 @@

    [meta.ref typedef-name — end note ]. Otherwise, false.

    -
    consteval bool is_function(info r);
    +
    consteval bool is_function(info r);

    24 Returns: true if r represents a function. Otherwise, false.

    -
    consteval bool is_conversion_function(info r);
    -consteval bool is_operator_function(info r);
    -consteval bool is_literal_operator(info r);
    +
    consteval bool is_conversion_function(info r);
    +consteval bool is_operator_function(info r);
    +consteval bool is_literal_operator(info r);

    25 Returns: true if r represents a conversion function, operator function, or literal operator, respectively. Otherwise, false.

    -
    consteval bool is_special_member_function(info r);
    -consteval bool is_constructor(info r);
    -consteval bool is_default_constructor(info r);
    -consteval bool is_copy_constructor(info r);
    -consteval bool is_move_constructor(info r);
    -consteval bool is_assignment(info r);
    -consteval bool is_copy_assignment(info r);
    -consteval bool is_move_assignment(info r);
    -consteval bool is_destructor(info r);
    +
    consteval bool is_special_member_function(info r);
    +consteval bool is_constructor(info r);
    +consteval bool is_default_constructor(info r);
    +consteval bool is_copy_constructor(info r);
    +consteval bool is_move_constructor(info r);
    +consteval bool is_assignment(info r);
    +consteval bool is_copy_assignment(info r);
    +consteval bool is_move_assignment(info r);
    +consteval bool is_destructor(info r);

    26 Returns: true if @@ -8193,7 +8034,7 @@

    [meta.ref assignment operator, a move assignment operator, or a prospective destructor, respectively. Otherwise, false.

    -
    consteval bool is_template(info r);
    +
    consteval bool is_template(info r);

    27 Returns: true if @@ -8209,15 +8050,15 @@

    [meta.ref is false. — end note ]

    -
    consteval bool is_function_template(info r);
    -consteval bool is_variable_template(info r);
    -consteval bool is_class_template(info r);
    -consteval bool is_alias_template(info r);
    -consteval bool is_conversion_function_template(info r);
    -consteval bool is_operator_function_template(info r);
    -consteval bool is_literal_operator_template(info r);
    -consteval bool is_constructor_template(info r);
    -consteval bool is_concept(info r);
    +
    consteval bool is_function_template(info r);
    +consteval bool is_variable_template(info r);
    +consteval bool is_class_template(info r);
    +consteval bool is_alias_template(info r);
    +consteval bool is_conversion_function_template(info r);
    +consteval bool is_operator_function_template(info r);
    +consteval bool is_literal_operator_template(info r);
    +consteval bool is_constructor_template(info r);
    +consteval bool is_concept(info r);

    29 Returns: true if @@ -8226,7 +8067,7 @@

    [meta.ref template, operator function template, literal operator template, constructor template, or concept respectively. Otherwise, false.

    -
    consteval bool has_template_arguments(info r);
    +
    consteval bool has_template_arguments(info r);

    30 Returns: true if @@ -8234,26 +8075,26 @@

    [meta.ref function template, variable template, class template, or an alias template. Otherwise, false.

    -
    consteval bool is_value(info r);
    -consteval bool is_object(info r);
    +
    consteval bool is_value(info r);
    +consteval bool is_object(info r);

    31 Returns: true if r represents a value or object, respectively. Otherwise, false.

    -
    consteval bool is_structured_binding(info r);
    +
    consteval bool is_structured_binding(info r);

    32 Returns: true if r represents a structured binding. Otherwise, false.

    -
    consteval bool is_class_member(info r);
    -consteval bool is_namespace_member(info r);
    -consteval bool is_nonstatic_data_member(info r);
    -consteval bool is_static_member(info r);
    -consteval bool is_base(info r);
    +
    consteval bool is_class_member(info r);
    +consteval bool is_namespace_member(info r);
    +consteval bool is_nonstatic_data_member(info r);
    +consteval bool is_static_member(info r);
    +consteval bool is_base(info r);

    33 Returns: true if @@ -8261,14 +8102,14 @@

    [meta.ref namespace member, non-static data member, static member, base class specifier, respectively. Otherwise, false.

    -
    consteval bool has_default_member_initializer(info r);
    +
    consteval bool has_default_member_initializer(info r);

    34 Returns: true if r represents a non-static data member that has a default member initializer. Otherwise, false.

    -
    consteval info type_of(info r);
    +
    consteval info type_of(info r);

    35 Constant When: r represents a value, object, variable, function that is not a constructor or @@ -8283,7 +8124,7 @@

    [meta.ref then the type of the base class. Otherwise, the type of any data member declared with the properties represented by r.

    -
    consteval info object_of(info r);
    +
    consteval info object_of(info r);

    37 Constant When: r is a reflection representing either an object or a variable denoting an @@ -8294,16 +8135,16 @@

    [meta.ref variable. Otherwise, r.

    Example 1: -
    int x;
    -int& y = x;
    -
    -static_assert(^x != ^y);                       // OK, x and y are different variables so their
    -                                               // reflections compare different
    -static_assert(object_of(^x) == object_of(^y)); // OK, because y is a reference
    -                                               // to x, their underlying objects are the same
    +
    int x;
    +int& y = x;
    +
    +static_assert(^x != ^y);                       // OK, x and y are different variables so their
    +                                               // reflections compare different
    +static_assert(object_of(^x) == object_of(^y)); // OK, because y is a reference
    +                                               // to x, their underlying objects are the same
    — end example ]
    -
    consteval info value_of(info r);
    +
    consteval info value_of(info r);

    39 Constant When: r is a reflection representing

    @@ -8335,17 +8176,17 @@

    [meta.ref
    Example 2: -
    constexpr int x = 0;
    -constexpr int y = 0;
    -
    -static_assert(^x != ^y);                         // OK, x and y are different variables so their
    -                                                 // reflections compare different
    -static_assert(value_of(^x) == value_of(^y));     // OK, both value_of(^x) and value_of(^y) represent
    -                                                 // the value 0
    -static_assert(value_of(^x) == reflect_value(0)); // OK, likewise
    +
    constexpr int x = 0;
    +constexpr int y = 0;
    +
    +static_assert(^x != ^y);                         // OK, x and y are different variables so their
    +                                                 // reflections compare different
    +static_assert(value_of(^x) == value_of(^y));     // OK, both value_of(^x) and value_of(^y) represent
    +                                                 // the value 0
    +static_assert(value_of(^x) == reflect_value(0)); // OK, likewise
    — end example ]
    -
    consteval info parent_of(info r);
    +
    consteval info parent_of(info r);

    41 Constant When: r represents a variable, structured binding, function, enumerator, class, class @@ -8357,7 +8198,7 @@

    [meta.ref Returns: A reflection of the class, function, or namespace that is the target scope ([basic.scope.scope]) of the first declaration of what is represented by r.

    -
    consteval info dealias(info r);
    +
    consteval info dealias(info r);

    43 Returns: If r represents a typedef-name or namespace @@ -8366,15 +8207,15 @@

    [meta.ref

    44

    Example 3: -
    using X = int;
    -using Y = X;
    -static_assert(dealias(^int) == ^int);
    -static_assert(dealias(^X) == ^int);
    -static_assert(dealias(^Y) == ^int);
    +
    using X = int;
    +using Y = X;
    +static_assert(dealias(^int) == ^int);
    +static_assert(dealias(^X) == ^int);
    +static_assert(dealias(^Y) == ^int);
    — end example ]
    -
    consteval info template_of(info r);
    -consteval vector<info> template_arguments_of(info r);
    +
    consteval info template_of(info r);
    +consteval vector<info> template_arguments_of(info r);

    45 Constant When: has_template_arguments(r) is true.

    @@ -8386,14 +8227,14 @@

    [meta.ref

    47

    Example 4: -
    template <class T, class U=T> struct Pair { };
    -template <class T> using PairPtr = Pair<T*>;
    -
    -static_assert(template_of(^Pair<int>) == ^Pair);
    -static_assert(template_arguments_of(^Pair<int>).size() == 2);
    -
    -static_assert(template_of(^PairPtr<int>) == ^PairPtr);
    -static_assert(template_arguments_of(^PairPtr<int>).size() == 1);
    +
    template <class T, class U=T> struct Pair { };
    +template <class T> using PairPtr = Pair<T*>;
    +
    +static_assert(template_of(^Pair<int>) == ^Pair);
    +static_assert(template_arguments_of(^Pair<int>).size() == 2);
    +
    +static_assert(template_of(^PairPtr<int>) == ^PairPtr);
    +static_assert(template_arguments_of(^PairPtr<int>).size() == 1);
    — end example ]

    @@ -8404,7 +8245,7 @@

    -
    consteval vector<info> members_of(info r);
    +
    consteval vector<info> members_of(info r);

    1 Constant When: r is a reflection representing either a namespace or a class type that is @@ -8458,7 +8299,7 @@

    Note 2: Base classes are not members. — end note ]

    -
    consteval vector<info> bases_of(info type);
    +
    consteval vector<info> bases_of(info type);

    6 Constant When: dealias(type) is a reflection representing a complete class type.

    @@ -8475,7 +8316,7 @@

    C.

    -
    consteval vector<info> static_data_members_of(info type);
    +
    consteval vector<info> static_data_members_of(info type);

    9 Constant When: dealias(type) represents a complete class type.

    @@ -8488,7 +8329,7 @@

    dealias(type), in the order in which they are declared.

    -
    consteval vector<info> nonstatic_data_members_of(info type);
    +
    consteval vector<info> nonstatic_data_members_of(info type);

    12 Constant When: dealias(type) represents a complete class type.

    @@ -8501,7 +8342,7 @@

    dealias(type), in the order in which they are declared.

    -
    consteval vector<info> enumerators_of(info type_enum);
    +
    consteval vector<info> enumerators_of(info type_enum);

    15 Constant When: dealias(type_enum) represents an enumeration type and has_complete_definition(dealias(type_enum)) @@ -8511,7 +8352,7 @@

    dealias(type_enum), in the order in which they are declared.

    -
    consteval vector<info> get_public_members(info type);
    +
    consteval vector<info> get_public_members(info type);

    17 Constant When: dealias(type) represents a complete class type.

    @@ -8525,7 +8366,7 @@

    is_public(e) is true, in order.

    -
    consteval vector<info> get_public_static_data_members(info type);
    +
    consteval vector<info> get_public_static_data_members(info type);

    20 Constant When: dealias(type) represents a complete class type.

    @@ -8539,7 +8380,7 @@

    is_public(e) is true, in order.

    -
    consteval vector<info> get_public_nonstatic_data_members(info type);
    +
    consteval vector<info> get_public_nonstatic_data_members(info type);

    23 Constant When: dealias(type) represents a complete class type.

    @@ -8553,7 +8394,7 @@

    is_public(e) is true, in order.

    -
    consteval vector<info> get_public_bases(info type);
    +
    consteval vector<info> get_public_bases(info type);

    26 Constant When: dealias(type) represents a complete class type.

    @@ -8575,10 +8416,10 @@

    [me
    -
    constexpr ptrdiff_t member_offset::total_bits() const;
    +
    constexpr ptrdiff_t member_offset::total_bits() const;

    1 Returns: bytes * CHAR_BIT + bits.

    -
    consteval member_offset offset_of(info r);
    +
    consteval member_offset offset_of(info r);

    2 Constant When: r represents a non-static data member, unnamed bit-field, or base class @@ -8600,7 +8441,7 @@

    [me

    4 Returns: {V / CHAR_BIT, V % CHAR_BIT}.

    -
    consteval size_t size_of(info r);
    +
    consteval size_t size_of(info r);

    5 Constant When: r is a reflection of a type, object, value, variable of non-reference type, @@ -8622,7 +8463,7 @@

    [me corresponding to a non-static data member of reference type has the same size and alignment as the corresponding pointer type. — end note ]

    -
    consteval size_t alignment_of(info r);
    +
    consteval size_t alignment_of(info r);

    7 Constant When: r is a reflection representing a type, object, variable, non-static data member @@ -8652,7 +8493,7 @@

    [me data member declared having the properties described by r. -
    consteval size_t bit_size_of(info r);
    +
    consteval size_t bit_size_of(info r);

    9 Constant When: r is a reflection of a type, object, value, variable of non-reference type, @@ -8681,8 +8522,8 @@

    [meta.refle

    2 The following are defined for exposition only to aid in the specification of extract:

    -
    template <class T>
    -  consteval T extract-ref(info r); // exposition only
    +
    template <class T>
    +  consteval T extract-ref(info r); // exposition only

    3 Note 1: T is a reference type. @@ -8695,8 +8536,8 @@

    [meta.refle is true.

    5 Returns: the object represented by object_of(r).

    -
    template <class T>
    -  consteval T extract-member-or-function(info r); // exposition only
    +
    template <class T>
    +  consteval T extract-member-or-function(info r); // exposition only

    6 Constant When:

      @@ -8727,8 +8568,8 @@

      [meta.refle

      7 Returns: a pointer value designating the entity represented by r.

      -
      template <class T>
      -  consteval T extract-val(info r); // exposition only
      +
      template <class T>
      +  consteval T extract-val(info r); // exposition only

      8 Let U be the type of the value or enumerator that r represents.

      @@ -8757,8 +8598,8 @@

      [meta.refle V represented by r, converted to T.

      -
      template <class T>
      -  consteval T extract(info r);
      +
      template <class T>
      +  consteval T extract(info r);

      11 Effects:

        @@ -8780,13 +8621,13 @@

        [
        -
        template <class R>
        -concept reflection_range =
        -  ranges::input_range<R> &&
        -  same_as<ranges::range_value_t<R>, info> &&
        -  same_as<remove_cvref_t<ranges::range_reference_t<R>>, info>;
        -
        template <reflection_range R = initializer_list<info>>
        -consteval bool can_substitute(info templ, R&& arguments);
        +
        template <class R>
        +concept reflection_range =
        +  ranges::input_range<R> &&
        +  same_as<ranges::range_value_t<R>, info> &&
        +  same_as<remove_cvref_t<ranges::range_reference_t<R>>, info>;
        +
        template <reflection_range R = initializer_list<info>>
        +consteval bool can_substitute(info templ, R&& arguments);

        1 Constant When: templ represents a template.

        @@ -8805,8 +8646,8 @@

        [

        4 Remarks: If attempting to substitute leads to a failure outside of the immediate context, the program is ill-formed.

        -
        template <reflection_range R = initializer_list<info>>
        -consteval info substitute(info templ, R&& arguments);
        +
        template <reflection_range R = initializer_list<info>>
        +consteval info substitute(info templ, R&& arguments);

        5 Constant When: can_substitute(templ, arguments) is true.

        @@ -8823,11 +8664,9 @@

        [

        [meta.reflection.result] Expression result reflection

        -
        -
        -
        -
        template <typename T>
        -  consteval info reflect_value(T expr);
        +

        ::: std ::: addu

        +
        template <typename T>
        +  consteval info reflect_value(T expr);

        1 Mandates: T is a structural type that is not a reference type.

        @@ -8859,8 +8698,8 @@

        expr. The type of the represented value is the cv-unqualified version of T.

        -
        template <typename T>
        -  consteval info reflect_object(T& expr);
        +
        template <typename T>
        +  consteval info reflect_object(T& expr);

        4 Mandates: T is not a function type.

        @@ -8886,8 +8725,8 @@

        6 Returns: A reflection of the object designated by expr.

        -
        template <typename T>
        -  consteval info reflect_function(T& expr);
        +
        template <typename T>
        +  consteval info reflect_function(T& expr);

        7 Mandates: T is a function type.

        @@ -8896,172 +8735,23 @@

        ^fn, where fn is the function designated by expr.

        -
        template <reflection_range R = initializer_list<info>>
        -  consteval info reflect_invoke(info target, R&& args);
        -template <reflection_range R1 = initializer_list<info>, reflection_range R2 = initializer_list<info>>
        -  consteval info reflect_invoke(info target, R1&& tmpl_args, R2&& args);
        -

        9 -An expression E is said to -be reciprocal to a reflection -r if

        -
          -
        • (9.1) -r represents a variable, -and E is an lvalue -designating the object named by that variable,
        • -
        • (9.2) -r represents an object or -function, and E is an -lvalue that designates that object or function, or
        • -
        • (9.3) -r represents a value, and -E is a prvalue that -computes that value.
        • -
        -

        10 -For exposition only, let

        -
          -
        • (10.1) -F be either an entity or an -expression, such that if target -represents a function or function template then -F is that entity, and if -target represents a variable, -object, or value, then F is -an expression reciprocal to -target,
        • -
        • (10.2) -TArgs... -be a sequence of entities and expressions corresponding to the elements -of tmpl_args (if any), such that for -every targ in -tmpl_args, -
            -
          • (10.2.1) -if targ represents a type -or typedef-name, the -corresponding element of -TArgs... -is that type, or the type named by that -typedef-name, -respectively,
          • -
          • (10.2.2) -if targ represents a -variable, object, value, or function, the corresponding element of -TArgs... -is an expression reciprocal to -targ, and
          • -
          • (10.2.3) -if targ represents a class -or alias template, then the corresponding element of -TArgs... -is that template,
          • -
        • -
        • (10.3) -Args... -be a sequence of expressions -{EK} corresponding to the -reflections -{rK} in -args, such that for every -rK that represents a -variable, object, value, or function, -EK is reciprocal to -rK,
        • -
        • (10.4) -Arg0 -be the first expression in -Args (if any), and
        • -
        • (10.5) -Args+... be -the sequence of expressions in -Args excluding -Arg0 -(if any),
        • -
        -

        and define an expression -INVOKE-EXPR as follows:

        -
          -
        • (10.6) -If target represents a non-member -function, variable, object, or value, then -INVOKE-EXPR is the -expression INVOKE(F, Arg0, Args+...).

        • -
        • (10.7) -Otherwise, if F is a member -function that is not a constructor, then -INVOKE-EXPR is the -expression Arg0.F(Args+...).

        • -
        • (10.8) -Otherwise, if F is a -function template that is not a constructor template, then -INVOKE-EXPR is either the -expression Arg0.template F<TArgs...>(Args+...) if -F is a member function -template, or F<TArgs...>(Arg0, Args+...) -otherwise.

        • -
        • (10.9) -Otherwise, if F is a -constructor or constructor template for a class -C, then -INVOKE-EXPR is an -expression C(Arg0, Args+...) -for which only F is -considered by overload resolution; furthermore, if -F is a constructor -template, then -TArgs... -are inferred as leading template arguments during template argument -deduction for F.

        • -
        -

        11 -Constant When:

        -
          -
        • target represents either a -function or function template, or a variable, object or value having -pointer-to-function, pointer-to-member, or closure type,
        • -
        • tmpl_args is empty unless -target represents a function -template,
        • -
        • every reflection in tmpl_args -represents a type, -typedef-name, class or -alias template, variable, object, value, or function,
        • -
        • every reflection in args -represents a variable, object, value, or function, and
        • -
        • the expression -INVOKE-EXPR is a -well-formed constant expression of structural type.
        • -
        -

        12 -Effects: If target -represents a function template, any specialization of the represented -template that would be invoked by evaluation of -INVOKE-EXPR is -instantiated.

        -

        13 -Returns: A reflection of the same result computed by -INVOKE-EXPR.

        -

        -
        -

        [meta.reflection.define_class] Reflection class definition generation

        -

        1 +

        1 The class data_member_options_t is a consteval-only type ([basic.types.general]), and is not a structural type ([temp.param]).

        -
        template <class T> requires constructible_from<u8string, T>
        -consteval data_member_options_t::name_type(T&& value);
        -

        2 +

        template <class T> requires constructible_from<u8string, T>
        +consteval data_member_options_t::name_type(T&& value);
        +

        2 Effects: Initializes contents with u8string(value).

        -
        template<class T> requires constructible_from<string, T>
        -consteval data_member_options_t::name_type(T&& value);
        -

        3 +

        template<class T> requires constructible_from<string, T>
        +consteval data_member_options_t::name_type(T&& value);
        +

        3 Effects: Initializes contents with string(value).

        @@ -9076,70 +8766,70 @@

        string, etc) or a UTF-8 string literal (or u8string_view, u8string, etc) equally well.

        -
        constexpr auto mem1 = data_member_spec(^int, {.name="ordinary_literal_encoding"});
        -constexpr auto mem2 = data_member_spec(^int, {.name=u8"utf8_encoding"});
        +
        constexpr auto mem1 = data_member_spec(^int, {.name="ordinary_literal_encoding"});
        +constexpr auto mem2 = data_member_spec(^int, {.name=u8"utf8_encoding"});
        — end note ]

        -
        consteval info data_member_spec(info type,
        -                                data_member_options_t options = {});
        -

        1 +

        consteval info data_member_spec(info type,
        +                                data_member_options_t options = {});
        +

        1 Constant When:

          -
        • (1.1) +
        • (1.1) type represents either a type cv T, or a typedef-name designating a type cv T;
        • -
        • (1.2) +
        • (1.2) if options.name.contents contains a value NAME then either:
            -
          • (1.2.1) +
          • (1.2.1) holds_alternative<u8string>(NAME) is true and get<u8string>(NAME) contains a valid identifier when interpreted with UTF-8, or
          • -
          • (1.2.2) +
          • (1.2.2) holds_alternative<string>(NAME) is true and get<string>(NAME) contains a valid identifier when interpreted with the ordinary literal encoding;
        • -
        • (1.3) +
        • (1.3) if options.alignment contains a value, it is an alignment value ([basic.align]) not less than the alignment requirement of T; and
        • -
        • (1.4) +
        • (1.4) if options.width contains a value V, then
        -

        2 +

        2 Returns: A reflection of a description of a declaration of a non-static data member declared with the type or typedef-name represented by type, and having the optional characteristics designated by options.

        -

        3 +

        3 Remarks: The returned reflection value is primarily useful in conjunction with define_class. Certain other functions in @@ -9148,16 +8838,16 @@

        identifier_of) can also be used to query the characteristics indicated by the arguments provided to data_member_spec.

        -
        consteval bool is_data_member_spec(info r);
        -

        4 +

        consteval bool is_data_member_spec(info r);
        +

        4 Returns: true if r represents a description of a declaration of a non-static data member. Otherwise, false.

        -
          template <reflection_range R = initializer_list<info>>
        -  consteval info define_class(info class_type, R&& mdescrs);
        -

        5 +

          template <reflection_range R = initializer_list<info>>
        +  consteval info define_class(info class_type, R&& mdescrs);
        +

        5 Constant When: Letting C be the class represented by class_type and @@ -9165,21 +8855,21 @@

        Kth reflection value in mdescrs,

          -
        • (5.1) +
        • (5.1) C is incomplete from every point in the evaluation context,
        • -
        • (5.2) +
        • (5.2) is_data_member_spec(rK) is true for every rK in mdescrs,
        • -
        • (5.3) +
        • (5.3) the type represented by type_of(rK) is a valid type for data members, for every rK in mdescrs, and
        • -
        • (5.4) +
        • (5.4) for every pair 0 ≤ K < L < mdescrs.size(), if has_identifier(rK) && has_identifier(rL) @@ -9190,7 +8880,7 @@

          C could be a class template specialization for which there is no reachable definition. — end note ]

          -

          6 +

          6 Let {tk} be a sequence of reflections and @@ -9198,30 +8888,30 @@

          data_member_options_t values such that

          -
          data_member_spec(tk, ok) == rk
          +
          data_member_spec(tk, ok) == rk

          for every rk in mdescrs.

          -

          7 +

          7 Effects: Produces an injected declaration D ([expr.const]) that provides a definition for C with properties as follows:

            -
          • (7.1) +
          • (7.1) The target scope of D is the scope to which C belongs ([basic.scope.scope]).
          • -
          • (7.2) +
          • (7.2) The locus of D follows immediately after the manifestly constant-evaluated expression currently under evaluation.
          • -
          • (7.3) +
          • (7.3) If C is a specialization of a class template T, then D is is an explicit specialization of T.
          • -
          • (7.4) +
          • (7.4) D contains a non-static data member corresponding to each reflection value rK in @@ -9233,28 +8923,28 @@

            rK precedes the declaration of rL.

          • -
          • (7.5) +
          • (7.5) The non-static data member corresponding to each rK is declared with the type or typedef-name represented by tK.
          • -
          • (7.6) +
          • (7.6) Non-static data members corresponding to reflections rK for which oK.no_unique_address is true are declared with the attribute [[no_unique_address]].
          • -
          • (7.7) +
          • (7.7) Non-static data members corresponding to reflections rK for which oK.width contains a value are declared as bit-fields whose width is that value.
          • -
          • (7.8) +
          • (7.8) Non-static data members corresponding to reflections rK for which oK.alignment contains a value are declared with the alignment-specifier alignas(oK.alignment).
          • -
          • (7.9) +
          • (7.9) Non-static data members corresponding to reflections rK are declared with names determined as follows: @@ -9269,16 +8959,16 @@

            u8identifier_of(rK) in UTF-8.

        • -
        • (7.10) +
        • (7.10) If C is a union type for which any of its members are not trivially default constructible, then it has a user-provided default constructor which has no effect.
        • -
        • (7.11) +
        • (7.11) If C is a union type for which any of its members are not trivially default destructible, then it has a user-provided default destructor which has no effect.
        -

        8 +

        8 Returns: class_type.

        @@ -9288,10 +8978,10 @@

        [meta.reflec
        -

        1 +

        1 Subclause [meta.reflection.unary] contains consteval functions that may be used to query the properties of a type at compile time.

        -

        2 +

        2 For each function taking an argument of type meta::info whose name contains type, a call to @@ -9312,44 +9002,44 @@

        [m
        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_TRAIT defined in this clause, std::meta::type_TRAIT(^T) equals the value of the corresponding unary type trait std::TRAIT_v<T> as specified in 21.3.5.2 [meta.unary.cat].

        -
        consteval bool type_is_void(info type);
        -consteval bool type_is_null_pointer(info type);
        -consteval bool type_is_integral(info type);
        -consteval bool type_is_floating_point(info type);
        -consteval bool type_is_array(info type);
        -consteval bool type_is_pointer(info type);
        -consteval bool type_is_lvalue_reference(info type);
        -consteval bool type_is_rvalue_reference(info type);
        -consteval bool type_is_member_object_pointer(info type);
        -consteval bool type_is_member_function_pointer(info type);
        -consteval bool type_is_enum(info type);
        -consteval bool type_is_union(info type);
        -consteval bool type_is_class(info type);
        -consteval bool type_is_function(info type);
        -consteval bool type_is_reflection(info type);
        -

        2

        +
        consteval bool type_is_void(info type);
        +consteval bool type_is_null_pointer(info type);
        +consteval bool type_is_integral(info type);
        +consteval bool type_is_floating_point(info type);
        +consteval bool type_is_array(info type);
        +consteval bool type_is_pointer(info type);
        +consteval bool type_is_lvalue_reference(info type);
        +consteval bool type_is_rvalue_reference(info type);
        +consteval bool type_is_member_object_pointer(info type);
        +consteval bool type_is_member_function_pointer(info type);
        +consteval bool type_is_enum(info type);
        +consteval bool type_is_union(info type);
        +consteval bool type_is_class(info type);
        +consteval bool type_is_function(info type);
        +consteval bool type_is_reflection(info type);
        +

        2

        Example 1: -
        namespace std::meta {
        -  consteval bool type_is_void(info type) {
        -    // one example implementation
        -    return extract<bool>(substitute(^is_void_v, {type}));
        -
        -    // another example implementation
        -    type = dealias(type);
        -    return type == ^void
        -        || type == ^const void
        -        || type == ^volatile void
        -        || type == ^const volatile void;
        -  }
        -}
        +
        namespace std::meta {
        +  consteval bool type_is_void(info type) {
        +    // one example implementation
        +    return extract<bool>(substitute(^is_void_v, {type}));
        +
        +    // another example implementation
        +    type = dealias(type);
        +    return type == ^void
        +        || type == ^const void
        +        || type == ^volatile void
        +        || type == ^const volatile void;
        +  }
        +}
        — end example ]
        @@ -9360,20 +9050,20 @@

        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_TRAIT defined in this clause, std::meta::type_TRAIT(^T) equals the value of the corresponding unary type trait std::TRAIT_v<T> as specified in 21.3.5.3 [meta.unary.comp].

        -
        consteval bool type_is_reference(info type);
        -consteval bool type_is_arithmetic(info type);
        -consteval bool type_is_fundamental(info type);
        -consteval bool type_is_object(info type);
        -consteval bool type_is_scalar(info type);
        -consteval bool type_is_compound(info type);
        -consteval bool type_is_member_pointer(info type);
        +
        consteval bool type_is_reference(info type);
        +consteval bool type_is_arithmetic(info type);
        +consteval bool type_is_fundamental(info type);
        +consteval bool type_is_object(info type);
        +consteval bool type_is_scalar(info type);
        +consteval bool type_is_compound(info type);
        +consteval bool type_is_member_pointer(info type);

        @@ -9382,7 +9072,7 @@

        [meta.ref
        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_UNARY-TRAIT @@ -9390,7 +9080,7 @@

        [meta.ref std::meta::type_UNARY-TRAIT(^T) equals the value of the corresponding type property std::UNARY-TRAIT_v<T> as specified in 21.3.5.4 [meta.unary.prop].

        -

        2 +

        2 For any types or typedef-names T and @@ -9399,7 +9089,7 @@

        [meta.ref std::meta::type_BINARY-TRAIT(^T, ^U) equals the value of the corresponding type property std::BINARY-TRAIT_v<T, U> as specified in 21.3.5.4 [meta.unary.prop].

        -

        3 +

        3 For any type or typedef-name T, pack of types or @@ -9411,71 +9101,71 @@

        [meta.ref defined in this clause, std::meta::type_VARIADIC-TRAIT(^T, r) equals the value of the corresponding type property std::VARIADIC-TRAIT_v<T, U...> as specified in 21.3.5.4 [meta.unary.prop].

        -
        consteval bool type_is_const(info type);
        -consteval bool type_is_volatile(info type);
        -consteval bool type_is_trivial(info type);
        -consteval bool type_is_trivially_copyable(info type);
        -consteval bool type_is_standard_layout(info type);
        -consteval bool type_is_empty(info type);
        -consteval bool type_is_polymorphic(info type);
        -consteval bool type_is_abstract(info type);
        -consteval bool type_is_final(info type);
        -consteval bool type_is_aggregate(info type);
        -consteval bool type_is_signed(info type);
        -consteval bool type_is_unsigned(info type);
        -consteval bool type_is_bounded_array(info type);
        -consteval bool type_is_unbounded_array(info type);
        -consteval bool type_is_scoped_enum(info type);
        -
        -template <reflection_range R = initializer_list<info>>
        -consteval bool type_is_constructible(info type, R&& type_args);
        -consteval bool type_is_default_constructible(info type);
        -consteval bool type_is_copy_constructible(info type);
        -consteval bool type_is_move_constructible(info type);
        -
        -consteval bool type_is_assignable(info type_dst, info type_src);
        -consteval bool type_is_copy_assignable(info type);
        -consteval bool type_is_move_assignable(info type);
        -
        -consteval bool type_is_swappable_with(info type_dst, info type_src);
        -consteval bool type_is_swappable(info type);
        -
        -consteval bool type_is_destructible(info type);
        -
        -template <reflection_range R = initializer_list<info>>
        -consteval bool type_is_trivially_constructible(info type, R&& type_args);
        -consteval bool type_is_trivially_default_constructible(info type);
        -consteval bool type_is_trivially_copy_constructible(info type);
        -consteval bool type_is_trivially_move_constructible(info type);
        -
        -consteval bool type_is_trivially_assignable(info type_dst, info type_src);
        -consteval bool type_is_trivially_copy_assignable(info type);
        -consteval bool type_is_trivially_move_assignable(info type);
        -consteval bool type_is_trivially_destructible(info type);
        -
        -template <reflection_range R = initializer_list<info>>
        -consteval bool type_is_nothrow_constructible(info type, R&& type_args);
        -consteval bool type_is_nothrow_default_constructible(info type);
        -consteval bool type_is_nothrow_copy_constructible(info type);
        -consteval bool type_is_nothrow_move_constructible(info type);
        -
        -consteval bool type_is_nothrow_assignable(info type_dst, info type_src);
        -consteval bool type_is_nothrow_copy_assignable(info type);
        -consteval bool type_is_nothrow_move_assignable(info type);
        -
        -consteval bool type_is_nothrow_swappable_with(info type_dst, info type_src);
        -consteval bool type_is_nothrow_swappable(info type);
        -
        -consteval bool type_is_nothrow_destructible(info type);
        -
        -consteval bool type_is_implicit_lifetime(info type);
        -
        -consteval bool type_has_virtual_destructor(info type);
        -
        -consteval bool type_has_unique_object_representations(info type);
        -
        -consteval bool type_reference_constructs_from_temporary(info type_dst, info type_src);
        -consteval bool type_reference_converts_from_temporary(info type_dst, info type_src);
        +
        consteval bool type_is_const(info type);
        +consteval bool type_is_volatile(info type);
        +consteval bool type_is_trivial(info type);
        +consteval bool type_is_trivially_copyable(info type);
        +consteval bool type_is_standard_layout(info type);
        +consteval bool type_is_empty(info type);
        +consteval bool type_is_polymorphic(info type);
        +consteval bool type_is_abstract(info type);
        +consteval bool type_is_final(info type);
        +consteval bool type_is_aggregate(info type);
        +consteval bool type_is_signed(info type);
        +consteval bool type_is_unsigned(info type);
        +consteval bool type_is_bounded_array(info type);
        +consteval bool type_is_unbounded_array(info type);
        +consteval bool type_is_scoped_enum(info type);
        +
        +template <reflection_range R = initializer_list<info>>
        +consteval bool type_is_constructible(info type, R&& type_args);
        +consteval bool type_is_default_constructible(info type);
        +consteval bool type_is_copy_constructible(info type);
        +consteval bool type_is_move_constructible(info type);
        +
        +consteval bool type_is_assignable(info type_dst, info type_src);
        +consteval bool type_is_copy_assignable(info type);
        +consteval bool type_is_move_assignable(info type);
        +
        +consteval bool type_is_swappable_with(info type_dst, info type_src);
        +consteval bool type_is_swappable(info type);
        +
        +consteval bool type_is_destructible(info type);
        +
        +template <reflection_range R = initializer_list<info>>
        +consteval bool type_is_trivially_constructible(info type, R&& type_args);
        +consteval bool type_is_trivially_default_constructible(info type);
        +consteval bool type_is_trivially_copy_constructible(info type);
        +consteval bool type_is_trivially_move_constructible(info type);
        +
        +consteval bool type_is_trivially_assignable(info type_dst, info type_src);
        +consteval bool type_is_trivially_copy_assignable(info type);
        +consteval bool type_is_trivially_move_assignable(info type);
        +consteval bool type_is_trivially_destructible(info type);
        +
        +template <reflection_range R = initializer_list<info>>
        +consteval bool type_is_nothrow_constructible(info type, R&& type_args);
        +consteval bool type_is_nothrow_default_constructible(info type);
        +consteval bool type_is_nothrow_copy_constructible(info type);
        +consteval bool type_is_nothrow_move_constructible(info type);
        +
        +consteval bool type_is_nothrow_assignable(info type_dst, info type_src);
        +consteval bool type_is_nothrow_copy_assignable(info type);
        +consteval bool type_is_nothrow_move_assignable(info type);
        +
        +consteval bool type_is_nothrow_swappable_with(info type_dst, info type_src);
        +consteval bool type_is_nothrow_swappable(info type);
        +
        +consteval bool type_is_nothrow_destructible(info type);
        +
        +consteval bool type_is_implicit_lifetime(info type);
        +
        +consteval bool type_has_virtual_destructor(info type);
        +
        +consteval bool type_has_unique_object_representations(info type);
        +
        +consteval bool type_reference_constructs_from_temporary(info type_dst, info type_src);
        +consteval bool type_reference_converts_from_temporary(info type_dst, info type_src);

        @@ -9484,7 +9174,7 @@

        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_PROP @@ -9492,16 +9182,16 @@

        std::meta::type_PROP(^T) equals the value of the corresponding type property std::PROP_v<T> as specified in 21.3.6 [meta.unary.prop.query].

        -

        2 +

        2 For any type or typedef-name T and unsigned integer value I, std::meta::type_extent(^T, I) equals std::extent_v<T, I> ([meta.unary.prop.query]).

        -
        consteval size_t type_alignment_of(info type);
        -consteval size_t type_rank(info type);
        -consteval size_t type_extent(info type, unsigned i = 0);
        +
        consteval size_t type_alignment_of(info type);
        +consteval size_t type_rank(info type);
        +consteval size_t type_extent(info type, unsigned i = 0);

        @@ -9510,10 +9200,10 @@

        [meta.reflection.
        -

        1 +

        1 The consteval functions specified in this clause may be used to query relationships between types at compile time.

        -

        2 +

        2 For any types or typedef-name T and @@ -9522,7 +9212,7 @@

        [meta.reflection. std::meta::type_REL(^T, ^U) equals the value of the corresponding type relation std::REL_v<T, U> as specified in 21.3.7 [meta.rel].

        -

        3 +

        3 For any type or typedef-name T, pack of types or @@ -9534,7 +9224,7 @@

        [meta.reflection. std::meta::type_VARIADIC-REL(^T, r) equals the value of the corresponding type relation std::VARIADIC-REL_v<T, U...> as specified in 21.3.7 [meta.rel].

        -

        4 +

        4 For any types or typedef-names T and @@ -9547,23 +9237,23 @@

        [meta.reflection. defined in this clause, std::meta::type_VARIADIC-REL-R(^R, ^T, r) equals the value of the corresponding type relation std::VARIADIC-REL-R_v<R, T, U...> as specified in 21.3.7 [meta.rel].

        -
        consteval bool type_is_same(info type1, info type2);
        -consteval bool type_is_base_of(info type_base, info type_derived);
        -consteval bool type_is_convertible(info type_src, info type_dst);
        -consteval bool type_is_nothrow_convertible(info type_src, info type_dst);
        -consteval bool type_is_layout_compatible(info type1, info type2);
        -consteval bool type_is_pointer_interconvertible_base_of(info type_base, info type_derived);
        -
        -template <reflection_range R = initializer_list<info>>
        -consteval bool type_is_invocable(info type, R&& type_args);
        -template <reflection_range R = initializer_list<info>>
        -consteval bool type_is_invocable_r(info type_result, info type, R&& type_args);
        -
        -template <reflection_range R = initializer_list<info>>
        -consteval bool type_is_nothrow_invocable(info type, R&& type_args);
        -template <reflection_range R = initializer_list<info>>
        -consteval bool type_is_nothrow_invocable_r(info type_result, info type, R&& type_args);
        -

        5 +

        consteval bool type_is_same(info type1, info type2);
        +consteval bool type_is_base_of(info type_base, info type_derived);
        +consteval bool type_is_convertible(info type_src, info type_dst);
        +consteval bool type_is_nothrow_convertible(info type_src, info type_dst);
        +consteval bool type_is_layout_compatible(info type1, info type2);
        +consteval bool type_is_pointer_interconvertible_base_of(info type_base, info type_derived);
        +
        +template <reflection_range R = initializer_list<info>>
        +consteval bool type_is_invocable(info type, R&& type_args);
        +template <reflection_range R = initializer_list<info>>
        +consteval bool type_is_invocable_r(info type_result, info type, R&& type_args);
        +
        +template <reflection_range R = initializer_list<info>>
        +consteval bool type_is_nothrow_invocable(info type, R&& type_args);
        +template <reflection_range R = initializer_list<info>>
        +consteval bool type_is_nothrow_invocable_r(info type_result, info type, R&& type_args);
        +

        5 Note 1: If t is a reflection of the type int and @@ -9585,7 +9275,7 @@

        -

        1 +

        1 Subclause [meta.reflection.trans] contains consteval functions that may be used to transform one type to another following some predefined rule.

        @@ -9597,19 +9287,19 @@

        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_MOD defined in this clause, std::meta::type_MOD(^T) returns the reflection of the corresponding type std::MOD_t<T> as specified in 21.3.8.2 [meta.trans.cv].

        -
        consteval info type_remove_const(info type);
        -consteval info type_remove_volatile(info type);
        -consteval info type_remove_cv(info type);
        -consteval info type_add_const(info type);
        -consteval info type_add_volatile(info type);
        -consteval info type_add_cv(info type);
        +
        consteval info type_remove_const(info type);
        +consteval info type_remove_volatile(info type);
        +consteval info type_remove_cv(info type);
        +consteval info type_add_const(info type);
        +consteval info type_add_volatile(info type);
        +consteval info type_add_cv(info type);

        @@ -9618,16 +9308,16 @@

        [m
        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_MOD defined in this clause, std::meta::type_MOD(^T) returns the reflection of the corresponding type std::MOD_t<T> as specified in 21.3.8.3 [meta.trans.ref].

        -
        consteval info type_remove_reference(info type);
        -consteval info type_add_lvalue_reference(info type);
        -consteval info type_add_rvalue_reference(info type);
        +
        consteval info type_remove_reference(info type);
        +consteval info type_add_lvalue_reference(info type);
        +consteval info type_add_rvalue_reference(info type);
        @@ -9636,15 +9326,15 @@

        [meta.
        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_MOD defined in this clause, std::meta::type_MOD(^T) returns the reflection of the corresponding type std::MOD_t<T> as specified in 21.3.8.4 [meta.trans.sign].

        -
        consteval info type_make_signed(info type);
        -consteval info type_make_unsigned(info type);
        +
        consteval info type_make_signed(info type);
        +consteval info type_make_unsigned(info type);
        @@ -9653,15 +9343,15 @@

        [meta.
        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_MOD defined in this clause, std::meta::type_MOD(^T) returns the reflection of the corresponding type std::MOD_t<T> as specified in 21.3.8.5 [meta.trans.arr].

        -
        consteval info type_remove_extent(info type);
        -consteval info type_remove_all_extents(info type);
        +
        consteval info type_remove_extent(info type);
        +consteval info type_remove_all_extents(info type);
        @@ -9670,15 +9360,15 @@

        [met
        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_MOD defined in this clause, std::meta::type_MOD(^T) returns the reflection of the corresponding type std::MOD_t<T> as specified in 21.3.8.6 [meta.trans.ptr].

        -
        consteval info type_remove_pointer(info type);
        -consteval info type_add_pointer(info type);
        +
        consteval info type_remove_pointer(info type);
        +consteval info type_add_pointer(info type);
        @@ -9697,7 +9387,7 @@

        [m
        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_MOD @@ -9705,7 +9395,7 @@

        [m std::meta::type_MOD(^T) returns the reflection of the corresponding type std::MOD_t<T> as specified in 21.3.8.7 [meta.trans.other].

        -

        2 +

        2 For any pack of types or typedef-names T... and @@ -9715,7 +9405,7 @@

        [m defined in this clause, std::meta::type_VARIADIC-MOD(r) returns the reflection of the corresponding type std::VARIADIC-MOD_t<T...> as specified in 21.3.8.7 [meta.trans.other].

        -

        3 +

        3 For any type or typedef-name T, pack of types or @@ -9726,29 +9416,29 @@

        [m std::meta::type_invoke_result(^T, r) returns the reflection of the corresponding type std::invoke_result_t<T, U...> (21.3.8.7 [meta.trans.other]).

        -
        consteval info type_remove_cvref(info type);
        -consteval info type_decay(info type);
        -template <reflection_range R = initializer_list<info>>
        -consteval info type_common_type(R&& type_args);
        -template <reflection_range R = initializer_list<info>>
        -consteval info type_common_reference(R&& type_args);
        -consteval info type_underlying_type(info type);
        -template <reflection_range R = initializer_list<info>>
        -consteval info type_invoke_result(info type, R&& type_args);
        -consteval info type_unwrap_reference(info type);
        -consteval info type_unwrap_ref_decay(info type);
        -

        4

        +
        consteval info type_remove_cvref(info type);
        +consteval info type_decay(info type);
        +template <reflection_range R = initializer_list<info>>
        +consteval info type_common_type(R&& type_args);
        +template <reflection_range R = initializer_list<info>>
        +consteval info type_common_reference(R&& type_args);
        +consteval info type_underlying_type(info type);
        +template <reflection_range R = initializer_list<info>>
        +consteval info type_invoke_result(info type, R&& type_args);
        +consteval info type_unwrap_reference(info type);
        +consteval info type_unwrap_ref_decay(info type);
        +

        4

        Example 1: -
        // example implementation
        -consteval info type_unwrap_reference(info type) {
        -  type = dealias(type);
        -  if (has_template_arguments(type) && template_of(type) == ^reference_wrapper) {
        -    return type_add_lvalue_reference(template_arguments_of(type)[0]);
        -  } else {
        -    return type;
        -  }
        -}
        +
        // example implementation
        +consteval info type_unwrap_reference(info type) {
        +  type = dealias(type);
        +  if (has_template_arguments(type) && template_of(type) == ^reference_wrapper) {
        +    return type_add_lvalue_reference(template_arguments_of(type)[0]);
        +  } else {
        +    return type;
        +  }
        +}
        — end example ]

        @@ -9759,7 +9449,7 @@

        -

        1 +

        1 For any type or typedef-name T, for each function std::meta::type_UNARY-TRAIT @@ -9767,7 +9457,7 @@

        std::meta::type_UNARY-TRAIT(^T) equals the value of the corresponding property std::UNARY-TRAIT_v<T> as defined in 22.4 [tuple] or 22.6 [variant].

        -

        2 +

        2 For any type or typedef-name T and value @@ -9776,11 +9466,11 @@

        std::meta::type_BINARY-TRAIT(I, ^T) returns a reflection representing the type std::BINARY-TRAIT_t<I, T> as defined in 22.4 [tuple] or 22.6 [variant].

        -
        consteval size_t type_tuple_size(info type);
        -consteval info type_tuple_element(size_t index, info type);
        -
        -consteval size_t type_variant_size(info type);
        -consteval info type_variant_alternative(size_t index, info type);
        +
        consteval size_t type_tuple_size(info type);
        +consteval info type_tuple_element(size_t index, info type);
        +
        +consteval size_t type_variant_size(info type);
        +consteval info type_variant_alternative(size_t index, info type);

        @@ -9791,7 +9481,7 @@

        22.15.3 22.15.3 [bit.cast]/3:

        -

        3 +

        3 Remarks: This function is constexpr if and only if To, From, and the types of all @@ -9799,27 +9489,27 @@

        22.15.3 From are types T such that:

        @@ -9837,10 +9527,10 @@

        -
          __cpp_impl_coroutine 201902L
        -  __cpp_impl_destroying_delete 201806L
        -  __cpp_impl_three_way_comparison 201907L
        -+ __cpp_impl_reflection 2024XXL
        +
          __cpp_impl_coroutine 201902L
        +  __cpp_impl_destroying_delete 201806L
        +  __cpp_impl_three_way_comparison 201907L
        ++ __cpp_impl_reflection 2024XXL

        @@ -9848,7 +9538,7 @@

        -
        + #define __cpp_lib_reflection 2024XXL // also in <meta>
        +
        + #define __cpp_lib_reflection 2024XXL // also in <meta>

        diff --git a/2996_reflection/reflection.md b/2996_reflection/reflection.md index 13458941..5bece4b1 100644 --- a/2996_reflection/reflection.md +++ b/2996_reflection/reflection.md @@ -30,7 +30,7 @@ Since [@P2996R7]: * renamed `(u8)operator_symbol_of` to `(u8)symbol_of` * renamed some `operators` (`exclaim` -> `exclamation_mark`, `three_way_comparison` -> `spaceship`, and `ampersand_and` -> `ampersand_ampersand`) -* removed `define_static_array` and `define_static_string` +* removed `define_static_array`, `define_static_string`, and `reflect_invoke` * clarified that `sizeof(std::meta::info) == `sizeof(void *)` * clarified that `data_member_options_t` is a non-structural consteval-only type * clarified that everything in `std::meta` is addressable @@ -1330,95 +1330,6 @@ static_assert(z == 2); On Compiler Explorer: [EDG](https://godbolt.org/z/MEYd3771Y), [Clang](https://godbolt.org/z/K4KWEqevv). -## Emulating typeful reflection -Although we believe a single opaque `std::meta::info` type to be the best and most scalable foundation for reflection, we acknowledge the desire expressed by SG7 for future support for "typeful reflection". The following demonstrates one possible means of assembling a typeful reflection library, in which different classes of reflections are represented by distinct types, on top of the facilities proposed here. - -::: std -```cpp -// Represents a 'std::meta::info' constrained by a predicate. -template - requires (std::predicate<[:type_of(Pred):], std::meta::info>) -struct metatype { - std::meta::info value; - - // Construction is ill-formed unless predicate is satisfied. - consteval metatype(std::meta::info r) : value(r) { - if (![:Pred:](r)) - throw "Reflection is not a member of this metatype"; - } - - // Cast to 'std::meta::info' allows values of this type to be spliced. - consteval operator std::meta::info() const { return value; } - - static consteval bool check(std::meta::info r) { return [:Pred:](r); } -}; - -// Type representing a "failure to match" any known metatypes. -struct unmatched { - consteval unmatched(std::meta::info) {} - static consteval bool check(std::meta::info) { return true; } -}; - -// Returns the given reflection "enriched" with a more descriptive type. -template -consteval std::meta::info enrich(std::meta::info r) { - // Because we control the type, we know that the constructor taking info is - // the first constructor. The copy/move constructors are added at the }, so - // will be the last ones in the list. - std::array ctors = { - *(members_of(^Choices) | std::views::filter(std::meta::is_constructor)).begin()..., - *(members_of(^unmatched) | std::views::filter(std::meta::is_constructor)).begin() - }; - std::array checks = {^Choices::check..., ^unmatched::check}; - - for (auto [check, ctor] : std::views::zip(checks, ctors)) - if (extract(reflect_invoke(check, {reflect_value(r)}))) - return reflect_invoke(ctor, {reflect_value(r)}); - - std::unreachable(); -} -``` -::: - -We can leverage this machinery to select different function overloads based on the "type" of reflection provided as an argument. - -::: std -```cpp -using type_t = metatype<^std::meta::is_type>; -using template_t = metatype<^std::meta::is_template>; - -// Example of a function overloaded for different "types" of reflections. -void PrintKind(type_t) { std::println("type"); } -void PrintKind(template_t) { std::println("template"); } -void PrintKind(unmatched) { std::println("unknown kind"); } - -int main() { - // Classifies any reflection as one of: Type, Function, or Unmatched. - auto enrich = [](std::meta::info r) { return ::enrich(r); }; - - // Demonstration of using 'enrich' to select an overload. - PrintKind([:enrich(^metatype):]); // "template" - PrintKind([:enrich(^type_t):]); // "type" - PrintKind([:enrich(std::meta::reflect_value(3):]); // "unknown kind" -} -``` -::: - -Note that the `metatype` class can be generalized to wrap values of any literal type, or to wrap multiple values of possibly different types. This has been used, for instance, to select compile-time overloads based on: whether two integers share the same parity, the presence or absence of a value in an `optional`, the type of the value held by a `variant` or an `any`, or the syntactic form of a compile-time string. - -Achieving the same in C++23, with the same generality, would require spelling the argument(s) twice: first to obtain a "classification tag" to use as a template argument, and again to call the function, i.e., - -::: std -```cpp -Printer::PrintKind(^int). -// or worse... -fn(Arg1, Arg2, Arg3). -``` -::: - -On Compiler Explorer: [Clang](https://godbolt.org/z/E8fc41s4q). - # Proposed Features ## The Reflection Operator (`^`) @@ -2384,12 +2295,6 @@ namespace std::meta { template > consteval auto substitute(info templ, R&& args) -> info; - // @[reflect_invoke](#reflect_invoke)@ - template > - consteval auto reflect_invoke(info target, R&& args) -> info; - template , reflection_range R2 = initializer_list> - consteval auto reflect_invoke(info target, R1&& tmpl_args, R2&& args) -> info; - // @[reflect expression results](#reflect-expression-results)@ template consteval auto reflect_value(T value) -> info; @@ -2694,29 +2599,6 @@ typename[:r:] si; // Error: T::X is invalid for T = int. `can_substitute(templ, args)` simply checks if the substitution can succeed (with the same caveat about instantiations outside of the immediate context). If `can_substitute(templ, args)` is `false`, then `substitute(templ, args)` will be ill-formed. -### `reflect_invoke` - -::: std -```c++ -namespace std::meta { - template > - consteval auto reflect_invoke(info target, R&& args) -> info; - template , reflection_range R2 = initializer_list> - consteval auto reflect_invoke(info target, R1&& tmpl_args, R2&& args) -> info; -} -``` -::: - -These metafunctions produce a reflection of the result of a call expression. - -For the first overload: Letting `F` be the entity represented by `target`, and `A@~0~@, A@~1~@, ..., A@~N~@` be the sequence of entities represented by the values held by `args`: if the expression `F(A@~0~@, A@~1~@, ..., A@~N~@)` is a well-formed constant expression evaluating to a structural type that is not `void`, and if every value in `args` is a reflection of a value or object usable in constant expressions, then `reflect_invoke(target, args)` evaluates to a reflection of the result of `F(A@~0~@, A@~1~@, ..., A@~N~@)`. For all other invocations, `reflect_invoke(target, args)` is not a constant expression. - -The second overload behaves the same as the first overload, except instead of evaluating `F(A@~0~@, A@~1~@, ..., A@~N~@)`, we require that `F` be a reflection of a template and evaluate `F(A@~0~@, A@~1~@, ..., A@~N~@)`. This allows evaluating `reflect_invoke(^std::get, {std::meta::reflect_value(0)}, {e})` to evaluate to, approximately, `^std::get<0>([: e :])`. - -If the returned reflection is of a value (rather than an object), the type of the reflected value is the cv-qualified (de-aliased) type of what's returned by the function. - -A few possible extensions for `reflect_invoke` have been discussed among the authors. Given the advent of constant evaluations with side-effects, it may be worth allowing `void`-returning functions, but this would require some representation of "a returned value of type `void`". Construction of runtime call expressions is another exciting possibility. Both extensions require more thought and implementation experience, and we are not proposing either at this time. - ### `reflect_value`, `reflect_object`, `reflect_function` {#reflect-expression-results} ::: std @@ -4481,11 +4363,6 @@ namespace std::meta { template consteval info reflect_function(T& fn); - template > - consteval info reflect_invoke(info target, R&& args); - template , reflection_range R2 = initializer_list> - consteval info reflect_invoke(info target, R1&& tmpl_args, R2&& args); - // [meta.reflection.define_class], class definition generation struct data_member_options_t { struct name_type { @@ -5469,55 +5346,6 @@ template [#]{.pnum} *Returns*: `^fn`, where `fn` is the function designated by `expr`. -```cpp -template > - consteval info reflect_invoke(info target, R&& args); -template , reflection_range R2 = initializer_list> - consteval info reflect_invoke(info target, R1&& tmpl_args, R2&& args); -``` - -[#]{.pnum} An expression `$E$` is said to be _reciprocal to_ a reflection `$r$` if - - - [#.#]{.pnum} `$r$` represents a variable, and `$E$` is an lvalue designating the object named by that variable, - - [#.#]{.pnum} `$r$` represents an object or function, and `$E$` is an lvalue that designates that object or function, or - - [#.#]{.pnum} `$r$` represents a value, and `$E$` is a prvalue that computes that value. - -[#]{.pnum} For exposition only, let - -- [#.#]{.pnum} `$F$` be either an entity or an expression, such that if `target` represents a function or function template then `$F$` is that entity, and if `target` represents a variable, object, or value, then `$F$` is an expression reciprocal to `target`, -- [#.#]{.pnum} `$TArgs$...` be a sequence of entities and expressions corresponding to the elements of `tmpl_args` (if any), such that for every `$targ$` in `tmpl_args`, - - [#.#.#]{.pnum} if `$targ$` represents a type or `$typedef-name$`, the corresponding element of `$TArgs$...` is that type, or the type named by that `$typedef-name$`, respectively, - - [#.#.#]{.pnum} if `$targ$` represents a variable, object, value, or function, the corresponding element of `$TArgs$...` is an expression reciprocal to `$targ$`, and - - [#.#.#]{.pnum} if `$targ$` represents a class or alias template, then the corresponding element of `$TArgs$...` is that template, -- [#.#]{.pnum} `$Args$...` be a sequence of expressions {`@$E$~$K$~@`} corresponding to the reflections {`@$r$~$K$~@`} in `args`, such that for every `@$r$~$K$~@` that represents a variable, object, value, or function, `@$E$~$K$~@` is reciprocal to `@$r$~$K$~@`, -- [#.#]{.pnum} `@$Arg$~0~@` be the first expression in `$Args$` (if any), and -- [#.#]{.pnum} `@$Args$~$+$~@...` be the sequence of expressions in `$Args$` excluding `@$Arg$~0~@` (if any), - -and define an expression `$INVOKE-EXPR$` as follows: - -- [#.#]{.pnum} If `target` represents a non-member function, variable, object, or value, then `$INVOKE-EXPR$` is the expression `$INVOKE$($F$, @$Arg$~0~@, @$Args$~$+$~@...)`. - -- [#.#]{.pnum} Otherwise, if `$F$` is a member function that is not a constructor, then `$INVOKE-EXPR$` is the expression `@$Arg$~0~@.$F$(@$Args$~$+$~@...)`. - -- [#.#]{.pnum} Otherwise, if `$F$` is a function template that is not a constructor template, then `$INVOKE-EXPR$` is either the expression `@$Arg$~0~@.template $F$<$TArgs$...>(@$Args$~$+$~@...)` if `$F$` is a member function template, or `$F$<$TArgs$...>(@$Arg$~0~@, @$Args$~$+$~@...)` otherwise. - -- [#.#]{.pnum} Otherwise, if `$F$` is a constructor or constructor template for a class `$C$`, then `$INVOKE-EXPR$` is an expression `$C$(@$Arg$~0~@, @$Args$~$+$~@...)` for which only `$F$` is considered by overload resolution; furthermore, if `$F$` is a constructor template, then `$TArgs$...` are inferred as leading template arguments during template argument deduction for `$F$`. - -[#]{.pnum} *Constant When*: - -- `target` represents either a function or function template, or a variable, object or value having pointer-to-function, pointer-to-member, or closure type, -- `tmpl_args` is empty unless `target` represents a function template, -- every reflection in `tmpl_args` represents a type, `$typedef-name$`, class or alias template, variable, object, value, or function, -- every reflection in `args` represents a variable, object, value, or function, and -- the expression `$INVOKE-EXPR$` is a well-formed constant expression of structural type. - -[#]{.pnum} *Effects*: If `target` represents a function template, any specialization of the represented template that would be invoked by evaluation of `$INVOKE-EXPR$` is instantiated. - -[#]{.pnum} *Returns*: A reflection of the same result computed by `$INVOKE-EXPR$`. - -::: -::: - ### [meta.reflection.define_class] Reflection class definition generation {-} ::: std