diff --git a/source/basic.tex b/source/basic.tex index ba0d605817..7464bb7eac 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -114,17 +114,33 @@ A \defn{variable} is introduced by the declaration of a reference other than a non-static data member or of -an object. The variable's name, if any, denotes the reference or object. +an object. \pnum -An \defn{entity} is a value, object, reference, +An \defn{entity} is a +variable, structured binding, result binding, -function, enumerator, type, -class member, bit-field, template, template specialization, namespace, or -pack. An entity $E$ is denoted by the name (if any) -that is introduced by a declaration of $E$ or -by a \grammarterm{typedef-name} introduced by a declaration specifying $E$. +function, +enumerator, +type, +type alias, +non-static data member, +bit-field, +template, +namespace, +namespace alias, +template parameter, +function parameter, or +\grammarterm{init-capture}. +The \defnadj{underlying}{entity} of an entity is that entity +unless otherwise specified. +A name \defnx{denotes}{denote} the underlying entity of +the entity declared by each declaration that introduces the name. +\begin{note} +Type aliases and namespace aliases have underlying entities +that are distinct from themselves. +\end{note} \pnum A \defnadj{local}{entity} is a variable with @@ -153,7 +169,7 @@ unit. If so, the declaration specifies the interpretation and semantic properties of these names. -A declaration of an entity or \grammarterm{typedef-name} $X$ is +A declaration of an entity $X$ is a redeclaration of $X$ if another declaration of $X$ is reachable from it\iref{module.reach}; otherwise, it is a \defnadj{first}{declaration}. @@ -221,12 +237,15 @@ \item it is an \grammarterm{alias-declaration}\iref{dcl.typedef}, \item it is -a -\grammarterm{using-declaration}\iref{namespace.udecl}, +a \grammarterm{namespace-alias-definition}\iref{namespace.alias}, +\item it is +a \grammarterm{using-declaration}\iref{namespace.udecl}, \item it is a \grammarterm{deduction-guide}\iref{temp.deduct.guide}, \item it is a \grammarterm{static_assert-declaration}\iref{dcl.pre}, +\item it is +a \grammarterm{consteval-block-declaration}, \item it is an \grammarterm{attribute-declaration}\iref{dcl.pre}, @@ -264,7 +283,6 @@ int X::y = 1; // defines \tcode{X::y} enum { up, down }; // defines \tcode{up} and \tcode{down} namespace N { int d; } // defines \tcode{N} and \tcode{N::d} -namespace N1 = N; // defines \tcode{N1} X anX; // defines \tcode{anX} \end{codeblock} @@ -275,6 +293,7 @@ int f(int); // declares \tcode{f} struct S; // declares \tcode{S} typedef int Int; // declares \tcode{Int} +namespace N1 = N; // declares \tcode{N1} extern X anotherX; // declares \tcode{anotherX} using N::d; // declares \tcode{d} \end{codeblock} @@ -368,8 +387,9 @@ The set of \defn{potential results} of an expression $E$ is defined as follows: \begin{itemize} -\item If $E$ is an -\grammarterm{id-expression}\iref{expr.prim.id}, the set +\item If $E$ is +an \grammarterm{id-expression}\iref{expr.prim.id} or +a \grammarterm{splice-expression}\iref{expr.prim.splice}, the set contains only $E$. \item If $E$ is a subscripting operation\iref{expr.sub} with an array operand, the set contains the potential results of that operand. @@ -395,17 +415,21 @@ \item Otherwise, the set is empty. \end{itemize} \begin{note} -This set is a (possibly-empty) set of \grammarterm{id-expression}{s}, +This set is a (possibly-empty) set of +\grammarterm{id-expression}{s} and \grammarterm{splice-expression}s, each of which is either $E$ or a subexpression of $E$. \begin{example} In the following example, the set of potential results of the initializer of \tcode{n} contains the first \tcode{S::x} subexpression, but not the second \tcode{S::x} subexpression. +The set of potential results of the initializer of \tcode{o} contains +the subexpression \tcode{[:\caret\caret S::x:]}. \begin{codeblock} struct S { static const int x = 0; }; const int &f(const int &r); int n = b ? (1, S::x) // \tcode{S::x} is not odr-used here : f(S::x); // \tcode{S::x} is odr-used here, so a definition is required +int o = [:^^S::x:]; \end{codeblock} \end{example} \end{note} @@ -453,7 +477,9 @@ \pnum \label{term.odr.use}% A variable is named by an expression -if the expression is an \grammarterm{id-expression} that denotes it. +if the expression is an \grammarterm{id-expression} or +\grammarterm{splice-expression}\iref{expr.prim.splice} +that designates it. A variable \tcode{x} that is named by a potentially-evaluated expression $N$ that appears at a point $P$ @@ -510,7 +536,12 @@ \end{example} \pnum -A structured binding is odr-used if it appears as a potentially-evaluated expression. +A structured binding is named by an expression +if that expression is either an \grammarterm{id-expression} or +a \grammarterm{splice-expression} +that designates that structured binding. +A structured binding is odr-used +if it is named by a potentially-evaluated expression. \pnum \tcode{*\keyword{this}} is odr-used if \keyword{this} appears as a potentially-evaluated expression @@ -696,7 +727,16 @@ \end{note} \pnum -For any definable item \tcode{D} with definitions in multiple translation units, +If a definable item \tcode{D} is defined in a translation unit +by an injected declaration $X$\iref{expr.const} and +another translation unit contains a definition of \tcode{D}, +that definition shall be an injected declaration +having the same characteristic sequence as $X$; +a diagnostic is required only if \tcode{D} is attached to a named module and +a prior definition is reachable at the point where a later definition occurs. + +\pnum +For any other definable item \tcode{D} with definitions in multiple translation units, \begin{itemize} \item if \tcode{D} is a non-inline non-templated function or variable, or @@ -722,7 +762,7 @@ is considered to consist of the sequence of tokens of the corresponding \grammarterm{lambda-expression}. \item In each such definition, corresponding names, looked up -according to~\ref{basic.lookup}, shall refer to the same entity, after +according to~\ref{basic.lookup}, shall denote the same entity, after overload resolution\iref{over.match} and after matching of partial template specializations\iref{temp.spec.partial.match}, except that a name can refer to \begin{itemize} @@ -738,7 +778,7 @@ \item a reference with internal or no linkage initialized with a constant expression such that -the reference refers to the same entity in all definitions of \tcode{D}. +the reference refers to the same object or function in all definitions of \tcode{D}. \end{itemize} \item In each such definition, except within @@ -767,11 +807,17 @@ \item In each such definition, a default argument used by an (implicit or explicit) function call or a default template argument used by an (implicit or explicit) -\grammarterm{template-id} or \grammarterm{simple-template-id} +\grammarterm{template-id}, +\grammarterm{simple-template-id}, or +\grammarterm{splice-specialization-specifier} is treated as if its token sequence were present in the definition of \tcode{D}; that is, the default argument or default template argument is subject to the requirements described in this paragraph (recursively). + +\item In each such definition, +corresponding \grammarterm{reflect-expression}s\iref{expr.reflect} +compute equivalent values\iref{expr.eq}. \end{itemize} \pnum @@ -926,6 +972,9 @@ Any names (re)introduced by a declaration are \defnx{bound}{name!bound} to it in its target scope. \end{itemize} +The \defnadj{host}{scope} of a declaration is +the inhabited scope if that scope is a block scope and +the target scope otherwise. An entity \defnx{belongs}{entity!belong} to a scope $S$ if $S$ is the target scope of a declaration of the entity. \begin{note} @@ -1006,7 +1055,7 @@ \item either is a \grammarterm{using-declarator}, or \item -one declares a type (not a \grammarterm{typedef-name}) and the other declares a +one declares a type (not a type alias) and the other declares a variable, non-static data member other than of an anonymous union\iref{class.union.anon}, enumerator, @@ -1663,7 +1712,7 @@ In certain contexts, only certain kinds of declarations are included. After any such restriction, any declarations of classes or enumerations are discarded if any other declarations are found. \begin{note} -A type (but not a \grammarterm{typedef-name} or template) +A type (but not a type alias or template) is therefore hidden by any other entity in its scope. \end{note} \indextext{type-only!lookup|see{lookup, type-only}}% @@ -1671,8 +1720,8 @@ only declarations of types and templates whose specializations are types are considered; furthermore, if declarations -of a \grammarterm{typedef-name} and of the type to which it refers are found, -the declaration of the \grammarterm{typedef-name} is discarded +of a type alias and of its underlying entity are found, +the declaration of the type alias is discarded instead of the type declaration. \rSec2[class.member.lookup]{Member name lookup}% @@ -2136,7 +2185,16 @@ The set of entities is determined in the following way: \begin{itemize} -\item If \tcode{T} is a fundamental type, its associated set of +\item If \tcode{T} is \tcode{std::meta::info}\iref{meta.reflection.synop}, +its associated set of entities is the singleton containing +the enumeration type \tcode{std::meta::operators}\iref{meta.reflection.operators}. +\begin{note} +The \tcode{std::meta::info} type is a type alias, +so an explicit rule is needed to associate calls +whose arguments are reflections with the namespace \tcode{std::meta}. +\end{note} + +\item If \tcode{T} is any other fundamental type, its associated set of entities is empty. \item If \tcode{T} is a class type (including unions), @@ -2294,8 +2352,14 @@ followed by a \tcode{::} scope resolution operator considers only namespaces, types, and templates whose specializations are types. -If a name, \grammarterm{template-id}, or \grammarterm{computed-type-specifier} +If a +name, +\grammarterm{template-id}, +\grammarterm{splice-scope-specifier}, or +\grammarterm{computed-type-specifier} is followed by a \tcode{::}, +it shall either be +a dependent \grammarterm{splice-scope-specifier}\iref{temp.dep.splice} or it shall designate a namespace, class, enumeration, or dependent type, and the \tcode{::} is never interpreted as a complete \grammarterm{nested-name-specifier}. @@ -2344,6 +2408,7 @@ \item a \grammarterm{typename-specifier}, \item a \grammarterm{qualified-namespace-specifier}, or \item a \grammarterm{nested-name-specifier}, +\grammarterm{reflection-name}, \grammarterm{elaborated-type-specifier}, or \grammarterm{class-or-decltype} that has a \grammarterm{nested-name-specifier}\iref{expr.prim.id.qual}. @@ -2738,6 +2803,70 @@ only namespace names are considered.% \indextext{lookup!name|)}% +\rSec1[basic.splice]{Splice specifiers} +\indextext{splice|(}% + +\begin{bnf} +\nontermdef{splice-specifier}\br + \terminal{[:} constant-expression \terminal{:]} +\end{bnf} + +\begin{bnf} +\nontermdef{splice-specialization-specifier}\br + splice-specifier \terminal{<} \opt{template-argument-list} \terminal{>} +\end{bnf} + +\pnum +The \grammarterm{constant-expression} of a \grammarterm{splice-specifier} +shall be a converted constant expression of +type \tcode{std::meta::info}\iref{expr.const}. +A \grammarterm{splice-specifier} +whose converted \grammarterm{constant-expression} represents +a construct $X$ is said to \defn{designate} either +\begin{itemize} +\item the underlying entity of $X$ if $X$ is an entity\iref{basic.pre}, or +\item $X$ otherwise. +\end{itemize} +\begin{note} +A \grammarterm{splice-specifier} is dependent +if the converted \grammarterm{constant-expression} is +value-dependent\iref{temp.dep.splice}. +\end{note} + +\pnum +A non-dependent \grammarterm{splice-specifier} of +a \grammarterm{splice-specialization-specifier} shall designate a template. + +\pnum +\begin{note} +A \tcode{<} following a \grammarterm{splice-specifier} is interpreted as +the delimiter of a \grammarterm{template-argument-list} +when the \grammarterm{splice-specifier} is preceded by +the keyword \keyword{template} or the keyword \keyword{typename}, or +when it appears in a type-only context\iref{temp.names}. +\begin{example} +\begin{codeblock} +constexpr int v = 1; +template struct TCls { + static constexpr int s = V + 1; +}; + +using alias = [:^^TCls:]<([:^^v:])>; + // OK, a \grammarterm{splice-specialization-specifier} with a \grammarterm{splice-expression} as a template argument + +static_assert(alias::s == 2); + +auto o1 = [:^^TCls:]<([:^^v:])>(); // error: < means less than +auto o2 = typename [:^^TCls:]<([:^^v:])>(); // OK, o2 is an object of type TCls<1> + +consteval int bad_splice(std::meta::info v) { + return [:v:]; // error: v is not constant +} +\end{codeblock} +\end{example} +\end{note} +\indextext{splice|)} + \rSec1[basic.link]{Program and linkage}% \indextext{linkage|(} @@ -2909,6 +3038,8 @@ \item they appear in the same translation unit, or \item +they both declare type aliases or namespace aliases that have the same underlying entity, or +\item they both declare names with module linkage and are attached to the same module, or \item they both declare names with external linkage. @@ -3021,6 +3152,16 @@ \item $D$ contains a \grammarterm{lambda-expression} whose closure type is $E$, \item +$D$ contains +a \grammarterm{reflect-expression} or a \grammarterm{splice-specifier} +that, respectively, represents or designates $E$, +\item +$D$ is an injected declaration\iref{expr.const} +whose characteristic sequence contains a reflection +that represents +a data member description ($T$, $N$, $A$, $W$, $\mathit{NUA}$)\iref{class.mem.general} +for which $T$ is $E$, +\item $E$ is not a function or function template and $D$ contains an \grammarterm{id-expression}, \grammarterm{type-specifier}, @@ -3069,7 +3210,7 @@ An entity is \defnx{TU-local}{TU-local!entity} if it is \begin{itemize} \item -a type, function, variable, or template that +a type, type alias, namespace, namespace alias, function, variable, or template that \begin{itemize} \item has a name with internal linkage, or @@ -3101,14 +3242,28 @@ A value or object is \defnx{TU-local}{TU-local!value or object} if either \begin{itemize} \item +it is of TU-local type, +\item it is, or is a pointer to, -a TU-local function or the object associated with a TU-local variable, or +a TU-local function or the object associated with a TU-local variable, \item it is an object of class or array type and any of its subobjects or any of the objects or functions to which its non-static data members of reference type refer -is TU-local and is usable in constant expressions. +is TU-local and is usable in constant expressions, or +\item +it is a reflection value\iref{basic.fundamental} that represents +\begin{itemize} +\item +an entity, value, or object that is TU-local, +\item +a direct base class relationship (\tcode{D}, \tcode{B})\iref{class.derived.general} +for which either \tcode{D} or \tcode{B} is TU-local, or +\item +a data member description ($T$, $N$, $A$, $W$, $\mathit{NUA}$)\iref{class.mem.general} +for which $T$ is TU-local. +\end{itemize} \end{itemize} \pnum @@ -3158,6 +3313,16 @@ void adl(double); inline void h(auto x) { adl(x); } // OK, but certain specializations are exposures + +constexpr std::meta::info r1 = ^^g<0>; // OK +namespace N2 { + static constexpr std::meta::info r2 = ^^g<1>; // OK, \tcode{r2} is TU-local +} +constexpr std::meta::info r3 = ^^f; // error: \tcode{r3} is an exposure of \tcode{f} + +constexpr auto ctx = std::meta::access_context::current(); +constexpr std::meta::info r4 = + std::meta::members_of(^^N2, ctx)[0]; // error: \tcode{r4} is an exposure of \tcode{N2::r2} \end{codeblocktu} \begin{codeblocktu}{Translation unit \#2} module A; @@ -5021,7 +5186,7 @@ \label{term.scalar.type}% Arithmetic types\iref{basic.fundamental}, enumeration types, pointer types, pointer-to-member types\iref{basic.compound}, -\tcode{std::nullptr_t}, +\tcode{std::meta::\brk{}info}, \tcode{std::nullptr_t}, and cv-qualified\iref{basic.type.qualifier} versions of these types are collectively called @@ -5093,6 +5258,21 @@ layout-compatible enumerations\iref{dcl.enum}, or layout-compatible standard-layout class types\iref{class.mem}. +\pnum +A type is \defn{consteval-only} if it is either +\tcode{std::meta::info} or +a type compounded from a consteval-only type\iref{basic.compound}. +Every object of consteval-only type shall be +\begin{itemize} +\item +the object associated with a constexpr variable or a subobject thereof, +\item +a template parameter object\iref{temp.param} or a subobject thereof, or +\item +an object whose lifetime begins and ends +during the evaluation of a core constant expression. +\end{itemize} + \rSec2[basic.fundamental]{Fundamental types} \pnum @@ -5399,6 +5579,95 @@ pointer-to-member conversions\iref{conv.ptr,conv.mem}. \tcode{\keyword{sizeof}(std::nullptr_t)} shall be equal to \tcode{\keyword{sizeof}(\keyword{void}*)}. +\pnum +A value of type \tcode{std::meta::info} is called a \defn{reflection}. +There exists a unique \defnadj{null}{reflection}; +every other reflection is a representation of +\begin{itemize} +\item a value of scalar type\iref{temp.param}, +\item an object with static storage duration\iref{basic.stc}, +\item a variable\iref{basic.pre}, +\item a structured binding\iref{dcl.struct.bind}, +\item a function\iref{dcl.fct}, +\item an enumerator\iref{dcl.enum}, +\item an annotation\iref{dcl.attr.grammar}, +\item a type alias\iref{dcl.typedef}, +\item a type\iref{basic.types}, +\item a class member\iref{class.mem}, +\item an unnamed bit-field\iref{class.bit}, +\item a class template\iref{temp.pre}, +\item a function template, +\item a variable template, +\item an alias template\iref{temp.alias}, +\item a concept\iref{temp.concept}, +\item a namespace alias\iref{namespace.alias}, +\item a namespace\iref{basic.namespace.general}, +\item a direct base class relationship\iref{class.derived.general}, or +\item a data member description\iref{class.mem.general}. +\end{itemize} +A reflection is said to \defn{represent} the corresponding construct. +\begin{note} +A reflection of a value can be produced by library functions such as +\tcode{std::meta::constant_of} and \tcode{std::meta::reflect_constant}. +\end{note} +\begin{example} +\begin{codeblock} +int arr[] = {1, 2, 3}; +auto [a1, a2, a3] = arr; +void fn(); +enum Enum { A }; +using Alias = int; +struct B {}; +struct S : B { + int mem; + int : 0; +}; +template struct TCls {}; +template void TFn(); +template int TVar; +template concept Concept = requires { true; }; +namespace NS {}; +namespace NSAlias = NS; + +constexpr auto ctx = std::meta::access_context::current(); + +constexpr auto r1 = std::meta::reflect_constant(42); // represents int value of 42 +constexpr auto r2 = std::meta::reflect_object(arr[1]); // represents int object +constexpr auto r3 = ^^arr; // represents a variable +constexpr auto r4 = ^^a3; // represents a structured binding +constexpr auto r5 = ^^fn; // represents a function +constexpr auto r6 = ^^Enum::A; // represents an enumerator +constexpr auto r7 = ^^Alias; // represents a type alias +constexpr auto r8 = ^^S; // represents a type +constexpr auto r9 = ^^S::mem; // represents a class member +constexpr auto r10 = std::meta::members_of(^^S, ctx)[1]; // represents an unnamed bit-field +constexpr auto r11 = ^^TCls; // represents a class template +constexpr auto r12 = ^^TFn; // represents a function template +constexpr auto r13 = ^^TVar; // represents a variable template +constexpr auto r14 = ^^Concept; // represents a concept +constexpr auto r15 = ^^NSAlias; // represents a namespace alias +constexpr auto r16 = ^^NS; // represents a namespace +constexpr auto r17 = std::meta::bases_of(^^S, ctx)[0]; // represents a direct base class relationship +constexpr auto r18 = + std::meta::data_member_spec(^^int, {.name="member"}); // represents a data member description +\end{codeblock} +\end{example} + +\pnum +\recommended +Implementations should not represent other constructs +specified in this document, such as +\grammarterm{using-declarator}s, +partial template specializations, +attributes, placeholder types, +statements, or +expressions, +as values of type \tcode{std::meta::info}. +\begin{note} +Future revisions of this document can specify semantics for reflections +representing any such constructs. +\end{note} + \pnum \indextext{type!fundamental}% The types described in this subclause @@ -6078,12 +6347,14 @@ \pnum \indextext{value computation|(}% -Reading an object designated by a \keyword{volatile} -glvalue\iref{basic.lval}, modifying an object, calling a library I/O -function, or calling a function that does any of those operations are -all -\defn{side effects}, which are changes in the state of the execution -environment. \defnx{Evaluation}{evaluation} of an expression (or a +Reading an object designated by a \keyword{volatile} glvalue\iref{basic.lval}, +modifying an object, +producing an injected declaration\iref{expr.const}, +calling a library I/O function, or +calling a function that does any of those operations +are all \defn{side effects}, +which are changes in the state of the execution or translation environment. +\defnx{Evaluation}{evaluation} of an expression (or a subexpression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and @@ -6256,6 +6527,14 @@ signal handler is usually unsequenced with respect to the rest of the program. \end{note} +\pnum +During the evaluation of an expression +as a core constant expression\iref{expr.const}, +evaluations of operands of individual operators and +of subexpressions of individual expressions +that are otherwise either unsequenced or indeterminately sequenced +are evaluated in lexical order. + \rSec2[intro.multithread]{Multi-threaded executions and data races} \rSec3[intro.multithread.general]{General} diff --git a/source/classes.tex b/source/classes.tex index a24602d91a..75ff18b5c5 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -555,6 +555,7 @@ using-declaration\br using-enum-declaration\br static_assert-declaration\br + consteval-block-declaration\br template-declaration\br explicit-specialization\br deduction-guide\br @@ -646,13 +647,14 @@ \end{note} \pnum -A \grammarterm{member-declaration} does not declare new members of the class +A \grammarterm{member-declaration} does not itself declare new members of the class if it is \begin{itemize} \item a friend declaration\iref{class.friend}, \item a \grammarterm{deduction-guide}\iref{temp.deduct.guide}, \item a \grammarterm{template-declaration} whose \grammarterm{declaration} is one of the above, \item a \grammarterm{static_assert-declaration}, +\item a \grammarterm{consteval-block-declaration}, \item a \grammarterm{using-declaration}\iref{namespace.udecl}, or \item an \grammarterm{empty-declaration}. \end{itemize} @@ -686,10 +688,21 @@ Any other data member or member function is a \defnadj{non-static}{member} (a \defnadj{non-static}{data member} or \defnadj{non-static}{member function}\iref{class.mfct.non.static}, respectively). -\begin{note} -A non-static data member of non-reference -type is a member subobject of a class object\iref{intro.object}. -\end{note} + +\pnum +Every object of class type has a unique member subobject +corresponding to each of its direct non-static data members. +If any non-static data member of a class \tcode{C} is of reference type, +then let \tcode{D} be an invented class +that is identical to \tcode{C} +except that each non-static member of \tcode{D} corresponding to +a member of \tcode{C} of type ``reference to \tcode{T}'' +instead has type ``pointer to \tcode{T}''. +Every member subobject of a complete object of type \tcode{C} +has the same size, alignment, and offset +as that of the corresponding subobject of a complete object of type \tcode{D}. +The size and alignment of \tcode{C} are the same as +the size and alignment of \tcode{D}. \pnum A member shall not be declared twice in the @@ -999,6 +1012,46 @@ pointer-interconvertible\iref{basic.compound,expr.static.cast}. \end{note} +\pnum +A \defnadj{data member}{description} is +a quintuple ($T$, $N$, $A$, $W$, $\mathit{NUA}$) +describing the potential declaration of a non-static data member where +\begin{itemize} +\item $T$ is a type, +\item $N$ is an identifier or $\bot$, +\item $A$ is an alignment or $\bot$, +\item $W$ is a bit-field width or $\bot$, and +\item $\mathit{NUA}$ is a boolean value. +\end{itemize} +Two data member descriptions are equal +if each of their respective components are the same entities, +are the same identifiers, have equal values, or are both $\bot$. +\begin{note} +The components of a data member description describe a data member such that +\begin{itemize} +\item +its type is specified using the type given by $T$, +\item +it is declared with the name given by $N$ +if $N$ is not $\bot$ and is otherwise unnamed, +\item +it is declared with the \grammarterm{alignment-specifier}\iref{dcl.align} +given by \tcode{alignas($A$)} +if $A$ is not $\bot$ and +is otherwise declared without an \grammarterm{alignment-specifier}, +\item +it is a bit-field\iref{class.bit} with the width given by $W$ +if W is not $\bot$ and is otherwise not a bit-field, and +\item +it is declared with +the attribute \tcode{[[no_unique_address]]}\iref{dcl.attr.nouniqueaddr} +if $\mathit{NUA}$ is true and is otherwise declared without that attribute. +\end{itemize} +Data member descriptions are represented by reflections\iref{basic.fundamental} +returned by \tcode{std::meta::data_member_spec}\iref{meta.reflection.define.aggregate} and +can be reified as data members of a class using \tcode{std::meta::define_aggregate}. +\end{note} + \rSec2[class.mfct]{Member functions}% \indextext{member function!class} @@ -3514,7 +3567,12 @@ The class denoted by the \grammarterm{class-or-decltype} of a \grammarterm{base-specifier} is called a \defnadj{direct}{base class} -for the class being defined. +for the class being defined; +for each such \grammarterm{base-specifier}, +the corresponding \defnadj{direct base class}{relationship} +is the ordered pair (\tcode{D}, \tcode{B}) +where \tcode{D} is the class being defined and +\tcode{B} is the direct base class. \indextext{base class}% \indextext{derivation|see{inheritance}}% The lookup for the component name of @@ -4345,9 +4403,10 @@ \end{codeblock} \end{example} \begin{note} -Because access control applies to the declarations named, if access control is applied to a -\grammarterm{typedef-name}, only the accessibility of the typedef or alias declaration itself is considered. -The accessibility of the entity referred to by the \grammarterm{typedef-name} is not considered. +Because access control applies to the declarations named, +if access control is applied to a type alias, +only the accessibility of the typedef or alias declaration itself is considered. +The accessibility of the underlying entity is not considered. \begin{example} \begin{codeblock} class A { @@ -4738,10 +4797,18 @@ to a pointer to a private or protected immediate base class of \tcode{X}. \end{note} -The access to a member is affected by the class in which the member is -named. -This naming class is -the class in whose scope name lookup performed a search that found the member. +An expression $E$ that designates a member \tcode{m} +has a \defnadj{designating}{class} +that affects the access to \tcode{m}. +This designating class is either +\begin{itemize} +\item +the innermost class of which \tcode{m} is directly a member +if $E$ is a \grammarterm{splice-expression} or +\item +the class in whose scope name lookup performed a search +that found \tcode{m} otherwise. +\end{itemize} \begin{note} This class can be explicit, e.g., when a \grammarterm{qualified-id} @@ -4753,7 +4820,7 @@ \grammarterm{qualified-id} are used to name the member (as in \tcode{p->T::m}), -the class naming the member is the class denoted by the +the class designating the member is the class designated by the \grammarterm{nested-name-specifier} of the \grammarterm{qualified-id} @@ -4764,11 +4831,13 @@ \tcode{m} is accessible at the point \placeholder{R} -when named in class +when designated in class \tcode{N} if \begin{itemize} \item +\tcode{m} is designated by a \grammarterm{splice-expression}, or +\item \tcode{m} as a member of \tcode{N} @@ -4810,7 +4879,7 @@ \tcode{m} is accessible at \placeholder{R} -when named in class +when designated in class \tcode{B}. \begin{example} \begin{codeblock} @@ -4836,10 +4905,10 @@ left operand (considered as a pointer in the ``\tcode{.}'' operator case) cannot be implicitly converted to a -pointer to the naming class of the right operand. +pointer to the designating class of the right operand. \begin{note} This requirement is in addition to the requirement that -the member be accessible as named. +the member be accessible as designated. \end{note} \rSec2[class.friend]{Friends}% diff --git a/source/compatibility.tex b/source/compatibility.tex index 8d1468e9cd..4904b17a86 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -13,6 +13,22 @@ \rSec2[diff.cpp23.lex]{\ref{lex}: Lexical conventions} +\diffref{lex.operators} +\change +New operator \tcode{\caret\caret}. +\rationale +Required for new features. +\effect +Valid \CppXXIII{} code that contains two consecutive \tcode{\caret} tokens +can be ill-formed in this revision of \Cpp{}. +\begin{example} +\begin{codeblock} +struct C { int operator^(int); }; +int operator^(int (C::*p)(int), C); +int i = &C::operator^^C{}; // ill-formed; previously well-formed +\end{codeblock} +\end{example} + \diffref{lex.key} \change New keywords. @@ -148,6 +164,22 @@ \end{codeblock} \end{example} +\diffref{dcl.attr.grammar} +\change +New token \tcode{:]}. +\rationale +Required for new features. +\effect +Valid \CppXXIII{} code that contained an \grammarterm{attribute-specifier} +with an \grammarterm{attribute-using-prefix} +but no attributes and no whitespace is ill-formed in this revision of \Cpp{}. +\begin{example} +\begin{codeblock} +struct [[using CC:]] C; // ill-formed; previously well-formed +struct [[using DD: ]] D; // OK +\end{codeblock} +\end{example} + \rSec2[diff.cpp23.temp]{\ref{temp}: templates} \diffref{temp.constr} @@ -221,6 +253,8 @@ \libheaderref{hive}, \libheaderrefx{inplace_vector}{inplace.vector.syn}, \libheaderref{linalg}, +%FIXME: \libheaderref{meta} after renaming to meta.syn +\libheaderrefx{meta}{meta.type.synop}, \libheaderref{rcu}, \libheaderref{simd}, \libheaderref{stdbit.h}, diff --git a/source/declarations.tex b/source/declarations.tex index 7c0c694c1d..973139b772 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -53,6 +53,7 @@ using-enum-declaration\br using-directive\br static_assert-declaration\br + consteval-block-declaration\br alias-declaration\br opaque-enum-declaration \end{bnf} @@ -102,6 +103,11 @@ \keyword{static_assert} \terminal{(} constant-expression \terminal{,} static_assert-message \terminal{)} \terminal{;} \end{bnf} +\begin{bnf} +\nontermdef{consteval-block-declaration}\br + \keyword{consteval} compound-statement +\end{bnf} + \begin{bnf} \nontermdef{empty-declaration}\br \terminal{;} @@ -245,8 +251,7 @@ If the \grammarterm{decl-specifier-seq} contains the \keyword{typedef} specifier, the declaration is a \defnx{typedef declaration}{declaration!typedef} and each \grammarterm{declarator-id} -is declared to be a \grammarterm{typedef-name}, synonymous with its -associated type\iref{dcl.typedef}. +is declared to be a \grammarterm{typedef-name}\iref{dcl.typedef}. \begin{note} Such a \grammarterm{declarator-id} is an \grammarterm{identifier}\iref{class.conv.fct}. @@ -382,6 +387,35 @@ \end{codeblock} \end{example} +\pnum +For a \grammarterm{consteval-block-declaration} $D$, +the expression $E$ corresponding to $D$ is: +\begin{codeblock} + [] -> void static consteval @\grammarterm{compound-statement}@ () +\end{codeblock} +$E$ shall be a constant expression\iref{expr.const}. +\begin{note} +The evaluation of the expression +corresponding to a \grammarterm{consteval-block-declaration}\iref{lex.phases} +can produce injected declarations as side effects. +\end{note} +\begin{example} +\begin{codeblock} +struct S; +consteval { + std::meta::define_aggregate(^^S, {}); // OK + + template + struct X { }; // error: local templates are not allowed + + template + concept C = true; // error: local concepts are not allowed + + return; // OK +} +\end{codeblock} +\end{example} + \pnum An \grammarterm{empty-declaration} has no effect. @@ -708,9 +742,8 @@ \pnum Declarations containing the \grammarterm{decl-specifier} \keyword{typedef} -declare identifiers that can be used later for naming -fundamental\iref{basic.fundamental} or compound\iref{basic.compound} -types. The \keyword{typedef} specifier shall not be +declare \defnadjx{type}{aliases}{alias}. +The \keyword{typedef} specifier shall not be combined in a \grammarterm{decl-specifier-seq} with any other kind of specifier except a \grammarterm{defining-type-specifier}, and it shall not be used in the \grammarterm{decl-specifier-seq} of a @@ -728,14 +761,12 @@ A name declared with the \keyword{typedef} specifier becomes a \grammarterm{typedef-name}. -A \grammarterm{typedef-name} names +The underlying entity of the type alias is the type associated with the \grammarterm{identifier}\iref{dcl.decl} or \grammarterm{simple-template-id}\iref{temp.pre}; \indextext{declaration!typedef@\tcode{typedef} as type}% \indextext{equivalence!type}% -\indextext{synonym!type name as}% -a \grammarterm{typedef-name} is thus a synonym for another type. A -\grammarterm{typedef-name} does not introduce a new type the way a class +A \grammarterm{typedef-name} does not introduce a new type the way a class declaration\iref{class.name} or enum declaration\iref{dcl.enum} does. \begin{example} After @@ -752,14 +783,14 @@ \end{example} \pnum -A \grammarterm{typedef-name} can also be introduced by an +A type alias can also be declared by an \grammarterm{alias-declaration}. The \grammarterm{identifier} following the -\tcode{using} keyword is not looked up; it becomes a \grammarterm{typedef-name} +\tcode{using} keyword is not looked up; +it becomes the \grammarterm{typedef-name} of a type alias and the optional \grammarterm{attribute-specifier-seq} following the -\grammarterm{identifier} appertains to that \grammarterm{typedef-name}. -Such a \grammarterm{typedef-name} has the same -semantics as if it were introduced by the \keyword{typedef} specifier. In -particular, it does not define a new type. +\grammarterm{identifier} appertains to that type alias. +Such a type alias has the same +semantics as if it were introduced by the \keyword{typedef} specifier. \begin{example} \begin{codeblock} using handler_t = void (*)(int); @@ -1377,7 +1408,8 @@ \begin{bnf} \nontermdef{computed-type-specifier}\br decltype-specifier\br - pack-index-specifier + pack-index-specifier\br + splice-type-specifier \end{bnf} \pnum @@ -1412,12 +1444,21 @@ is a placeholder for a type to be deduced\iref{dcl.spec.auto}. \indextext{deduction!class template arguments}% -A \grammarterm{type-specifier} of the form -\opt{\keyword{typename}} \opt{\grammarterm{nested-name-specifier}} \grammarterm{template-name} -is a placeholder for -a deduced class type\iref{dcl.type.class.deduct}. -The \grammarterm{nested-name-specifier}, if any, shall be non-dependent and -the \grammarterm{template-name} shall name a deducible template. +A \grammarterm{type-specifier} is a placeholder for +a deduced class type\iref{dcl.type.class.deduct} if either +\begin{itemize} +\item +it is of the form +\opt{\keyword{typename}} \opt{\grammarterm{nested-name-specifier}} \grammarterm{template-name} or +\item +it is of the form \opt{\keyword{typename}} \grammarterm{splice-specifier} and +the \grammarterm{splice-specifier} designates +a class template or alias template. +\end{itemize} +The \grammarterm{nested-name-specifier} or \grammarterm{splice-specifier}, +if any, shall be non-dependent and +the \grammarterm{template-name} or \grammarterm{splice-specifier} +shall designate a deducible template. A \defnadj{deducible}{template} is either a class template or is an alias template whose \grammarterm{defining-type-id} is of the form @@ -1455,6 +1496,7 @@ \grammarterm{placeholder-type-specifier} & the type as defined in~\ref{dcl.spec.auto}\\ \grammarterm{template-name} & the type as defined in~\ref{dcl.type.class.deduct}\\ +\grammarterm{splice-type-specifier} & the type as defined in~\ref{dcl.type.splice}\\ \tcode{char} & ``\tcode{char}'' \\ \tcode{unsigned char} & ``\tcode{unsigned char}'' \\ \tcode{signed char} & ``\tcode{signed char}'' \\ @@ -1683,6 +1725,10 @@ type of the entity named by $E$. If there is no such entity, the program is ill-formed; +\item otherwise, if $E$ is an unparenthesized \grammarterm{splice-expression}, +\tcode{decltype($E$)} is the type of the entity, object, or value +designated by the \grammarterm{splice-specifier} of $E$; + \item otherwise, if $E$ is an xvalue, \tcode{decltype($E$)} is \tcode{T\&\&}, where \tcode{T} is the type of $E$; @@ -1706,11 +1752,13 @@ decltype(i) x2; // type is \tcode{int} decltype(a->x) x3; // type is \tcode{double} decltype((a->x)) x4 = x3; // type is \tcode{const double\&} +decltype([:^^x1:]) x5 = 18; // type is \tcode{const int\&\&} +decltype(([:^^x1:])) x6 = 19; // type is \tcode{const int\&} void f() { [](auto ...pack) { - decltype(pack...[0]) x5; // type is \tcode{int} - decltype((pack...[0])) x6; // type is \tcode{int\&} + decltype(pack...[0]) x7; // type is \tcode{int} + decltype((pack...[0])) x8; // type is \tcode{int\&} }(0); } \end{codeblock} @@ -2266,6 +2314,59 @@ container e{5, 6}; // error: \tcode{int} is not an iterator \end{codeblock} \end{example} + +\rSec3[dcl.type.splice]{Type splicing} + +\begin{bnf} +\nontermdef{splice-type-specifier}\br + \opt{\keyword{typename}} splice-specifier\br + \opt{\keyword{typename}} splice-specialization-specifier +\end{bnf} + +\pnum +A \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} +immediately followed by \tcode{::} +is never interpreted as part of a \grammarterm{splice-type-specifier}. +A \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} +not preceded by \keyword{typename} +is only interpreted as a \grammarterm{splice-type-specifier} +within a type-only context\iref{temp.res.general}. +\begin{example} +\begin{codeblock} +template void tfn() { + typename [:R:]::type m; // OK, \keyword{typename} applies to the qualified name +} + +struct S { using type = int; }; +void fn() { + [:^^S::type:] *var; // error: \tcode{[:\caret\caret S::type:]} is an expression + typename [:^^S::type:] *var; // OK, declares variable with type \tcode{int*} +} + +using alias = [:^^S::type:]; // OK, type-only context +\end{codeblock} +\end{example} + +\pnum +For a \grammarterm{splice-type-specifier} of the form +\opt{\keyword{typename}} \grammarterm{splice-specifier}, +the \grammarterm{splice-specifier} shall designate +a type, a class template, or an alias template. +The \grammarterm{splice-type-specifier} designates +the same entity as the \grammarterm{splice-specifier}. + +\pnum +For a \grammarterm{splice-type-specifier} of the form +\opt{\keyword{typename}} \grammarterm{splice-specialization-specifier}, +the \grammarterm{splice-specifier} of +the \grammarterm{splice-specialization-specifier} +shall designate a template \tcode{T} +that is either a class template or an alias template. +The \grammarterm{splice-type-specifier} designates +the specialization of \tcode{T} corresponding to +the template argument list of the \grammarterm{splice-specialization-specifier}. \indextext{specifier|)}% \rSec1[dcl.decl]{Declarators}% @@ -3276,7 +3377,7 @@ \end{ncsimplebnf} and the \grammarterm{nested-name-specifier} -denotes a class, +designates a class, and the type of the contained \grammarterm{declarator-id} in the declaration \tcode{T} \tcode{D1} @@ -3289,6 +3390,7 @@ \tcode{T}''. The optional \grammarterm{attribute-specifier-seq}\iref{dcl.attr.grammar} appertains to the pointer-to-member. +The \grammarterm{nested-name-specifier} shall not designate an anonymous union. \pnum \begin{example} @@ -3469,8 +3571,10 @@ and the type of the array is ``array of \tcode{N} \tcode{U}''. \pnum -Furthermore, if there is a reachable declaration of the entity that inhabits the same -scope in which the bound was specified, an omitted array bound is taken to +Furthermore, if there is a reachable declaration of the entity +that specifies a bound and +has the same host scope\iref{basic.scope.scope}, +an omitted array bound is taken to be the same as in that earlier declaration, and similarly for the definition of a static data member of a class. \begin{example} @@ -3487,6 +3591,9 @@ extern int x[]; int i = sizeof(x); // error: incomplete object type } + +namespace A { extern int z[3]; } +int A::z[] = {}; // OK, defines an array of 3 elements \end{codeblock} \end{example} @@ -3839,7 +3946,7 @@ \pnum A function type with a \grammarterm{cv-qualifier-seq} or a -\grammarterm{ref-qualifier} (including a type named by +\grammarterm{ref-qualifier} (including a type denoted by \grammarterm{typedef-name}\iref{dcl.typedef,temp.param}) shall appear only as: \begin{itemize} @@ -3855,15 +3962,18 @@ \item the \grammarterm{type-id} of a \grammarterm{template-argument} for a \grammarterm{type-parameter}\iref{temp.arg.type}. + +\item the operand of a \grammarterm{reflect-expression}\iref{expr.reflect}. \end{itemize} \begin{example} \begin{codeblock} typedef int FIC(int) const; -FIC f; // error: does not declare a member function +FIC f; // error: does not declare a member function struct S { - FIC f; // OK + FIC f; // OK }; -FIC S::*pm = &S::f; // OK +FIC S::*pm = &S::f; // OK +constexpr std::meta::info yeti = ^^void(int) const &; // OK \end{codeblock} \end{example} @@ -4220,9 +4330,9 @@ \pnum For non-template functions, default arguments can be added in later declarations of a -function that inhabit the same scope. -Declarations that inhabit different -scopes have completely distinct sets of default arguments. +function that have the same host scope. +Declarations that have different +host scopes have completely distinct sets of default arguments. That is, declarations in inner scopes do not acquire default arguments from declarations in outer scopes, and vice versa. @@ -4393,9 +4503,19 @@ int h(int a, int b = sizeof(a)); // OK, unevaluated operand\iref{term.unevaluated.operand} \end{codeblock} \end{example} -A non-static member shall not appear in a default argument unless it appears as -the \grammarterm{id-expression} of a class member access expression\iref{expr.ref} or -unless it is used to form a pointer to member\iref{expr.unary.op}. +A non-static member shall not be designated in a default argument unless +\begin{itemize} +\item +it is designated by +the \grammarterm{id-expression} or \grammarterm{splice-expression} +of a class member access expression\iref{expr.ref}, +\item +it is designated by an expression +used to form a pointer to member\iref{expr.unary.op}, or +\item +it appears as the operand of +a \grammarterm{reflect-expression}\iref{expr.reflect}. +\end{itemize} \begin{example} The declaration of \tcode{X::mem1()} @@ -4407,8 +4527,10 @@ int b; class X { int a; - int mem1(int i = a); // error: non-static member \tcode{a} used as default argument - int mem2(int i = b); // OK; use \tcode{X::b} + int mem1(int i = a); // error: non-static member \tcode{a} used as default argument + int mem2(int i = b); // OK, use \tcode{X::b} + consteval void mem3(std::meta::info r = ^^a) {} // OK + int mem4(int i = [:^^a:]); // error: non-static member a designated in default argument static int b; }; \end{codeblock} @@ -4433,10 +4555,13 @@ int (*p2)() = &f; // error: type mismatch \end{codeblock} \end{example} +\begin{note} When an overload set contains a declaration of a function -that inhabits a scope $S$, -any default argument associated with any reachable declaration that inhabits $S$ -is available to the call. +whose host scope is $S$, +any default argument associated with any reachable declaration +whose host scope is $S$ +is available to the call\iref{over.match.viable}. +\end{note} \begin{note} The candidate might have been found through a \grammarterm{using-declarator} from which the declaration that provides the default argument is not reachable. @@ -4895,20 +5020,16 @@ \indextext{initialization!default}% \indextext{variable!indeterminate uninitialized}% \indextext{initialization!zero-initialization}% -To -\defnx{zero-initialize}{zero-initialization} -an object or reference of type -\tcode{T} -means: +To \defnx{zero-initialize}{zero-initialization} +an object or reference of type \tcode{T} means: \begin{itemize} \item -if -\tcode{T} -is a scalar type\iref{term.scalar.type}, the -object -is initialized to the value obtained by converting the integer literal \tcode{0} -(zero) to -\tcode{T}; +if \tcode{T} is \tcode{std::meta::info}, +the object is initialized to a null reflection value; +\item +if \tcode{T} is any other scalar type\iref{term.scalar.type}, +the object is initialized to the value +obtained by converting the integer literal \tcode{0} (zero) to \tcode{T}; \begin{footnote} As specified in~\ref{conv.ptr}, converting an integer literal whose value is @@ -4974,6 +5095,9 @@ shall be met and each element is default-initialized. +\item +If \tcode{T} is \tcode{std::meta::info}, the object is zero-initialized. + \item Otherwise, no initialization is performed. @@ -5002,8 +5126,9 @@ \end{itemize} If a program calls for the default-initialization of an object of a -const-qualified type \tcode{T}, -\tcode{T} shall be a const-default-constructible class type or array thereof. +const-qualified type \tcode{T}, \tcode{T} shall be +\tcode{std::meta::\linebreak info} or a const-default-constructible class type or +array thereof. \pnum To @@ -7003,8 +7128,10 @@ deleted definition or a function that is implicitly defined as deleted. \pnum -A program that refers to a deleted function implicitly or explicitly, other -than to declare it, is ill-formed. +A construct that designates a deleted function implicitly or explicitly, +other than to declare it or to appear as the operand of +a \grammarterm{reflect-expression}\iref{expr.reflect}, +is ill-formed. \recommended The resulting diagnostic message should include @@ -7993,11 +8120,15 @@ \begin{bnf} \nontermdef{using-enum-declarator}\br \opt{nested-name-specifier} identifier\br - \opt{nested-name-specifier} simple-template-id + \opt{nested-name-specifier} simple-template-id\br + splice-type-specifier \end{bnf} \pnum -A \grammarterm{using-enum-declarator} +A \grammarterm{using-enum-declarator} of +the form \grammarterm{splice-type-specifier} +designates the same type designated by the \grammarterm{splice-type-specifier}. +Any other \grammarterm{using-enum-declarator} names the set of declarations found by type-only lookup\iref{basic.lookup.general} for the \grammarterm{using-enum-declarator}\iref{basic.lookup.unqual,basic.lookup.qual}. @@ -8261,7 +8392,7 @@ \grammarterm{unnamed-namespace-definition} and all occurrences of \exposid{unique} in a translation unit are replaced by the same identifier, and this identifier differs from all other -identifiers in the translation unit. +identifiers in the program. The optional \grammarterm{attribute-specifier-seq} in the \grammarterm{unnamed-namespace-definition} appertains to \exposid{unique}. @@ -8293,8 +8424,8 @@ \indextext{synonym} \pnum -A \grammarterm{namespace-alias-definition} declares an alternate name for a -namespace according to the following grammar: +A \grammarterm{namespace-alias-definition} declares a \defnadj{namespace}{alias} +according to the following grammar: \begin{bnf} \nontermdef{namespace-alias}\br @@ -8303,7 +8434,8 @@ \begin{bnf} \nontermdef{namespace-alias-definition}\br - \keyword{namespace} identifier \terminal{=} qualified-namespace-specifier \terminal{;} + \keyword{namespace} identifier \terminal{=} qualified-namespace-specifier \terminal{;}\br + \keyword{namespace} identifier \terminal{=} splice-specifier \terminal{;}\br \end{bnf} \begin{bnf} @@ -8311,10 +8443,19 @@ \opt{nested-name-specifier} namespace-name \end{bnf} +\pnum +The \grammarterm{splice-specifier} (if any) +shall designate a namespace that is not the global namespace. + \pnum The \grammarterm{identifier} in a \grammarterm{namespace-alias-definition} -becomes a \grammarterm{namespace-alias} and denotes the namespace denoted by the -\grammarterm{qualified-namespace-specifier}. +becomes a \grammarterm{namespace-alias}. + +\pnum +The underlying entity\iref{basic.pre} of the namespace alias is +the namespace either +denoted by the \grammarterm{qualified-namespace-specifier} or +designated by the \grammarterm{splice-specifier}. \begin{note} When looking up a \grammarterm{namespace-name} in a \grammarterm{namespace-alias-definition}, only namespace names are @@ -8326,9 +8467,18 @@ \begin{bnf} \nontermdef{using-directive}\br - \opt{attribute-specifier-seq} \keyword{using} \keyword{namespace} \opt{nested-name-specifier} namespace-name \terminal{;} + \opt{attribute-specifier-seq} \keyword{using} \keyword{namespace} \opt{nested-name-specifier} namespace-name \terminal{;}\br + \opt{attribute-specifier-seq} \keyword{using} \keyword{namespace} splice-specifier \terminal{;} \end{bnf} +\pnum +The \grammarterm{splice-specifier} (if any) shall designate a namespace +that is not the global namespace. +The \grammarterm{nested-name-specifier}, +\grammarterm{namespace-name}, and +\grammarterm{splice-specifier} +shall not be dependent. + \pnum A \grammarterm{using-directive} shall not appear in class scope, but may appear in namespace scope or in block scope. @@ -8341,13 +8491,13 @@ \pnum \begin{note} -A \grammarterm{using-directive} makes the names in the nominated +A \grammarterm{using-directive} makes the names in the designated namespace usable in the scope in which the \grammarterm{using-directive} appears after the \grammarterm{using-directive}\iref{basic.lookup.unqual,namespace.qual}. During unqualified name lookup, the names appear as if they were declared in the nearest enclosing namespace which -contains both the \grammarterm{using-directive} and the nominated +contains both the \grammarterm{using-directive} and the designated namespace. \end{note} @@ -8388,8 +8538,8 @@ \pnum \begin{note} A \grammarterm{using-directive} is transitive: if a scope contains a -\grammarterm{using-directive} that nominates a namespace that itself -contains \grammarterm{using-directive}{s}, the namespaces nominated by those +\grammarterm{using-directive} that designates a namespace that itself +contains \grammarterm{using-directive}{s}, the namespaces designated by those \grammarterm{using-directive}{s} are also eligible to be considered. \end{note} \begin{example} @@ -9210,7 +9360,7 @@ \pnum \indextext{attribute!syntax and semantics}% -Attributes specify additional information for various source constructs +Attributes and annotations specify additional information for various source constructs such as types, variables, names, contract assertions, blocks, or translation units. \begin{bnf} @@ -9221,6 +9371,7 @@ \begin{bnf} \nontermdef{attribute-specifier}\br \terminal{[} \terminal{[} \opt{attribute-using-prefix} attribute-list \terminal{]} \terminal{]}\br + \terminal{[} \terminal{[} annotation-list \terminal{]} \terminal{]}\br alignment-specifier \end{bnf} @@ -9243,11 +9394,22 @@ attribute-list \terminal{,} attribute \terminal{...} \end{bnf} +\begin{bnf} +\nontermdef{annotation-list}\br + annotation \opt{\terminal{...}}\br + annotation-list \terminal{,} annotation \opt{\terminal{...}} +\end{bnf} + \begin{bnf} \nontermdef{attribute}\br attribute-token \opt{attribute-argument-clause} \end{bnf} +\begin{bnf} +\nontermdef{annotation}\br + \terminal{=} constant-expression +\end{bnf} + \begin{bnf} \nontermdef{attribute-token}\br identifier\br @@ -9280,7 +9442,8 @@ \terminal{(} \opt{balanced-token-seq} \terminal{)}\br \terminal{[} \opt{balanced-token-seq} \terminal{]}\br \terminal{\{} \opt{balanced-token-seq} \terminal{\}}\br - \textnormal{any \grammarterm{token} other than a parenthesis, a bracket, or a brace} + \terminal{[:} \opt{balanced-token-seq} \terminal{:]}\br + \textnormal{any \grammarterm{token} other than \terminal{(}, \terminal{)}, \terminal{[}, \terminal{]}, \terminal{\{}, \terminal{\}}, \terminal{[:}, or \terminal{:]}} \end{bnf} \pnum @@ -9319,8 +9482,11 @@ In an \grammarterm{attribute-list}, an ellipsis may appear only if that \grammarterm{attribute}'s specification permits it. An \grammarterm{attribute} followed by an ellipsis is a pack expansion\iref{temp.variadic}. -An \grammarterm{attribute-specifier} that contains no \grammarterm{attribute}{s} has no -effect. The order in which the \grammarterm{attribute-token}{s} appear in an +An \grammarterm{attribute-specifier} that contains +an \grammarterm{attribute-list} with no \grammarterm{attribute}s +and no \grammarterm{alignment-specifier} +has no effect. +The order in which the \grammarterm{attribute-token}{s} appear in an \grammarterm{attribute-list} is not significant. If a keyword\iref{lex.key} or an alternative token\iref{lex.digraph} that satisfies the syntactic requirements @@ -9331,6 +9497,10 @@ \grammarterm{attribute-token}. The \grammarterm{attribute-token} determines additional requirements on the \grammarterm{attribute-argument-clause} (if any). +\pnum +An \grammarterm{annotation} followed by an ellipsis +is a pack expansion\iref{temp.variadic}. + \pnum Each \grammarterm{attribute-specifier-seq} is said to \defn{appertain} to some entity or statement, identified by the syntactic context @@ -9575,7 +9745,7 @@ \pnum The attribute may be applied to the declaration of a class, -a \grammarterm{typedef-name}, +a type alias, a variable, a non-static data member, a function, @@ -9793,7 +9963,7 @@ \pnum The attribute may be applied to the declaration of a class, -\grammarterm{typedef-name}, +type alias, variable (including a structured binding declaration), structured binding, result binding\iref{dcl.contract.res}, @@ -10028,5 +10198,58 @@ if their respective types are all empty. \end{example} +\rSec2[dcl.attr.annotation]{Annotations}% +\indextext{attribute!annotations} + +\pnum +An annotation may be applied to any declaration of a +type, +type alias, +variable, +function, +namespace, +enumerator, +\grammarterm{base-specifier}, or +non-static data member. + +\pnum +Let $E$ be the expression +\tcode{std::meta::reflect_constant(\grammarterm{constant-expression})}. +%FIXME: weird "shall". +%I think we would usually say that E simply is a constant expression. +$E$ shall be a constant expression; +the result of $E$ is the \defnadj{underlying}{constant} of the annotation. + +\pnum +Each \grammarterm{annotation} produces a unique annotation. + +\pnum +Substituting into an \grammarterm{annotation} +is not in the immediate context. +\begin{example} +\begin{codeblock} +[[=1]] void f(); +[[=2, =3, =2]] void g(); +void g [[=4, =2]] (); +\end{codeblock} +\tcode{f} has one annotation +and \tcode{g} has five annotations. +These can be queried with metafunctions +such as \tcode{std::\brk{}meta::\brk{}anno\-tations_of}\iref{meta.reflection.annotation}. +\end{example} +\begin{example} +\begin{codeblock} +template + [[=T::type()]] void f(T t); + +void f(int); + +void g() { + f(0); // OK + f('0'); // error, substituting into the annotation results in an invalid expression +} +\end{codeblock} +\end{example} + \indextext{attribute|)}% \indextext{declaration|)} diff --git a/source/expressions.tex b/source/expressions.tex index a885859f4c..f7bcb1ad0d 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -147,7 +147,7 @@ \end{importgraphic} \begin{itemize} -\item A \defn{glvalue} is an expression whose evaluation determines the identity of an object or function. +\item A \defn{glvalue} is an expression whose evaluation determines the identity of an object, function, or non-static data member. \item A \defn{prvalue} is an expression whose evaluation initializes an object or computes the value of an operand of an operator, as specified by the context in which it appears, @@ -186,7 +186,8 @@ \begin{note} An expression is an xvalue if it is: \begin{itemize} -\item a move-eligible \grammarterm{id-expression}\iref{expr.prim.id.unqual}, +\item a move-eligible \grammarterm{id-expression}\iref{expr.prim.id.unqual} +or \grammarterm{splice-expression}\iref{expr.prim.splice}, \item the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type\iref{expr.call}, @@ -442,6 +443,7 @@ expr.typeid, expr.sizeof, expr.unary.noexcept, +expr.reflect, dcl.type.decltype, temp.pre, temp.concept}. @@ -467,6 +469,7 @@ \item \tcode{(} \grammarterm{expression} \tcode{)}, where \grammarterm{expression} is one of these expressions, \item \grammarterm{id-expression}\iref{expr.prim.id}, +\item \grammarterm{splice-expression}\iref{expr.prim.splice}, \item subscripting\iref{expr.sub}, \item class member access\iref{expr.ref}, \item indirection\iref{expr.unary.op}, @@ -1243,7 +1246,8 @@ id-expression\br lambda-expression\br fold-expression\br - requires-expression + requires-expression\br + splice-expression \end{bnf} \rSec2[expr.prim.literal]{Literals} @@ -1389,6 +1393,9 @@ $E$ is not the \grammarterm{id-expression} of a class member access expression\iref{expr.ref}, and \item +$E$ is not the \grammarterm{id-expression} of +a \grammarterm{reflect-expression}\iref{expr.reflect}, and +\item if $E$ is a \grammarterm{qualified-id}, $E$ is not the un-parenthesized operand of the unary \tcode{\&} operator\iref{expr.unary.op}, @@ -1446,7 +1453,8 @@ \end{itemize} \pnum -An \grammarterm{id-expression} that denotes a non-static data member or +An \grammarterm{id-expression} or \grammarterm{splice-expression} +that designates a non-static data member or implicit object member function of a class can only be used: \begin{itemize} \item as part of a class member access @@ -1459,7 +1467,8 @@ \item to form a pointer to member\iref{expr.unary.op}, or -\item if that \grammarterm{id-expression} denotes a non-static data member +\item if that \grammarterm{id-expression} or \grammarterm{splice-expression} +designates a non-static data member and it appears in an unevaluated operand. \begin{example} \begin{codeblock} @@ -1468,6 +1477,7 @@ }; int i = sizeof(S::m); // OK int j = sizeof(S::m + 42); // OK +int S::*k = &[:^^S::m:]; // OK \end{codeblock} \end{example} \end{itemize} @@ -1775,10 +1785,12 @@ a variable with automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. -An \grammarterm{id-expression} is \defn{move-eligible} if +An \grammarterm{id-expression} or +\grammarterm{splice-expression}\iref{expr.prim.splice} +is \defn{move-eligible} if \begin{itemize} \item -it names an implicitly movable entity, +it designates an implicitly movable entity, \item it is the (possibly parenthesized) operand of a \tcode{return}\iref{stmt.return} or @@ -1787,7 +1799,7 @@ \item each intervening scope between the declaration of the entity and -the innermost enclosing scope of the \grammarterm{id-expression} +the innermost enclosing scope of the expression is a block scope and, for a \grammarterm{throw-expression}, is not the block scope of @@ -1813,9 +1825,15 @@ type-name \terminal{::}\br namespace-name \terminal{::}\br computed-type-specifier \terminal{::}\br + splice-scope-specifier \terminal{::}\br nested-name-specifier identifier \terminal{::}\br nested-name-specifier \opt{\keyword{template}} simple-template-id \terminal{::} \end{bnf} +\begin{bnf} +\nontermdef{splice-scope-specifier}\br + splice-specifier\br + \opt{\keyword{template}} splice-specialization-specifier +\end{bnf} \pnum \indextext{component name}% @@ -1828,6 +1846,33 @@ \grammarterm{simple-template-id}, and/or \grammarterm{nested-name-specifier}. +\pnum +A \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} +that is not followed by \tcode{::} +is never interpreted as part of a \grammarterm{splice-scope-specifier}. +The keyword \keyword{template} may only be omitted +from the form +\tcode{\opt{\keyword{template}} \grammarterm{splice-specialization-specifier} ::} +when the \grammarterm{splice-specialization-specifier} +is preceded by \keyword{typename}. +\begin{example} +\begin{codeblock} +template +struct TCls { + static constexpr int s = V; + using type = int; +}; + +int v1 = [:^^TCls<1>:]::s; +int v2 = template [:^^TCls:]<2>::s; // OK, \keyword{template} binds to \grammarterm{splice-scope-specifier} +typename [:^^TCls:]<3>::type v3 = 3; // OK, \keyword{typename} binds to the qualified name +template [:^^TCls:]<3>::type v4 = 4; // OK, \keyword{template} binds to the \grammarterm{splice-scope-specifier} +typename template [:^^TCls:]<3>::type v5 = 5; // OK, same as \tcode{v3} +[:^^TCls:]<3>::type v6 = 6; // error: unexpected \tcode{<} +\end{codeblock} +\end{example} + \pnum A \grammarterm{nested-name-specifier} is \defn{declarative} if it is part of \begin{itemize} @@ -1842,17 +1887,44 @@ a declarative \grammarterm{nested-name-specifier}. \end{itemize} A declarative \grammarterm{nested-name-specifier} -shall not have a \grammarterm{computed-type-specifier}. +shall not have a \grammarterm{computed-type-specifier} or +a \grammarterm{splice-scope-specifier}. A declaration that uses a declarative \grammarterm{nested-name-specifier} shall be a friend declaration or inhabit a scope that contains the entity being redeclared or specialized. \pnum -The \grammarterm{nested-name-specifier} \tcode{::} nominates +The entity designated by a \grammarterm{nested-name-specifier} +is determined as follows: +\begin{itemize} +\item +The \grammarterm{nested-name-specifier} \tcode{::} designates the global namespace. +\item A \grammarterm{nested-name-specifier} with a \grammarterm{computed-type-specifier} -nominates the type denoted by the \grammarterm{computed-type-specifier}, +designates the same type designated by the \grammarterm{computed-type-specifier}, which shall be a class or enumeration type. +\item +For a \grammarterm{nested-name-specifier} of +the form \tcode{\grammarterm{splice-specifier} ::}, +the \grammarterm{splice-specifier} shall designate +a class or enumeration type or a namespace. +The \grammarterm{nested-name-specifier} designates the same entity +as the \grammarterm{splice-specifier}. +\item +For a \grammarterm{nested-name-specifier} of +the form +\tcode{\opt{\keyword{template}} \grammarterm{splice-specialization-specifier} ::}, +the \grammarterm{splice-specifier} of +the \grammarterm{splice-specialization-specifier} shall designate +a class template or an alias template $T$. +Letting $S$ be the specialization of $T$ +corresponding to the template argument list of +the \grammarterm{splice-specialization-specifier}, +$S$ shall either be a class template specialization or +an alias template specialization that denotes a class or enumeration type. +The \grammarterm{nested-name-specifier} designates the underlying entity of $S$. +\item If a \grammarterm{nested-name-specifier} $N$ is declarative and has a \grammarterm{simple-template-id} with a template argument list $A$ @@ -1863,22 +1935,24 @@ \item If $A$ is the template argument list\iref{temp.arg} of the corresponding \grammarterm{template-head} $H$\iref{temp.mem}, -$N$ nominates the primary template of $T$; +$N$ designates the primary template of $T$; $H$ shall be equivalent to the \grammarterm{template-head} of $T$\iref{temp.over.link}. \item -Otherwise, $N$ nominates the partial specialization\iref{temp.spec.partial} of $T$ +Otherwise, $N$ designates the partial specialization\iref{temp.spec.partial} of $T$ whose template argument list is equivalent to $A$\iref{temp.over.link}; the program is ill-formed if no such partial specialization exists. \end{itemize} -Any other \grammarterm{nested-name-specifier} nominates -the entity denoted by its +\item +Any other \grammarterm{nested-name-specifier} designates +the entity denotes by its \grammarterm{type-name}, \grammarterm{namespace-name}, \grammarterm{identifier}, or \grammarterm{simple-template-id}. If the \grammarterm{nested-name-specifier} is not declarative, the entity shall not be a template. +\end{itemize} \pnum A \grammarterm{qualified-id} shall not be of the form @@ -2133,6 +2207,10 @@ called the \defn{closure type}, whose properties are described below. +\pnum +The closure type is not complete +until the end of its corresponding \grammarterm{compound-statement}. + \pnum The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding @@ -2172,6 +2250,8 @@ respectively, and whose \grammarterm{template-parameter-list} consists of the specified \grammarterm{template-parameter-list}, if any. +The function call operator or the function call operator template are +direct members of the closure type. The \grammarterm{requires-clause} of the function call operator template is the \grammarterm{requires-clause} immediately following \tcode{<}~\grammarterm{template-parameter-list}{}~\tcode{>}, if any. @@ -2524,7 +2604,9 @@ }; \end{codeblock} \end{example} -Further, a variable \mname{func} is implicitly defined at the beginning of +Unless the \grammarterm{compound-statement} is +that of a \grammarterm{consteval-block-declaration}\iref{dcl.pre}, +a variable \mname{func} is implicitly defined at the beginning of the \grammarterm{compound-statement} of the \grammarterm{lambda-expression}, with semantics as described in~\ref{dcl.fct.def.general}. @@ -3271,13 +3353,16 @@ \begin{bnf} \nontermdef{type-requirement}\br - \keyword{typename} \opt{nested-name-specifier} type-name \terminal{;} + \keyword{typename} \opt{nested-name-specifier} type-name \terminal{;}\br + \keyword{typename} splice-specifier\br + \keyword{typename} splice-specialization-specifier \end{bnf} \pnum A \grammarterm{type-requirement} asserts the validity of a type. The component names of a \grammarterm{type-requirement} are those of its -\grammarterm{nested-name-specifier} (if any) and \grammarterm{type-name}. +\grammarterm{nested-name-specifier} (if any) and +\grammarterm{type-name} (if any). \begin{note} The enclosing \grammarterm{requires-expression} will evaluate to \keyword{false} if substitution of template arguments fails. @@ -3288,10 +3373,12 @@ template using Ref = T&; template concept C = requires { - typename T::inner; // required nested member name - typename S; // required valid\iref{temp.names} \grammarterm{template-id}; - // fails if \tcode{T::type} does not exist as a type to which \tcode{0} can be implicitly converted - typename Ref; // required alias template substitution, fails if \tcode{T} is void + typename T::inner; // required nested member name + typename S; // required valid\iref{temp.names} \grammarterm{template-id}; fails if \tcode{T::type} does not exist as a type + // to which \tcode{0} can be implicitly converted + typename Ref; // required alias template substitution, fails if \tcode{T} is void + typename [:T::r1:]; // fails if \tcode{T::r1} is not a reflection of a type + typename [:T::r2:]; // fails if \tcode{T::r2} is not a reflection of a template \tcode{Z} for which \tcode{Z} is a type }; \end{codeblock} \end{example} @@ -3426,6 +3513,150 @@ \indextext{expression!requires|)} \indextext{expression!primary|)} +\rSec2[expr.prim.splice]{Expression splicing} + +\begin{bnf} +\nontermdef{splice-expression}\br + splice-specifier\br + \keyword{template} splice-specifier\br + \keyword{template} splice-specialization-specifier +\end{bnf} + +\pnum +A +\grammarterm{splice-specifier} or \grammarterm{splice-specialization-specifier} +immediately followed by \tcode{::} or preceded by \keyword{typename} +is never interpreted as part of a \grammarterm{splice-expression}. +\begin{example} +\begin{codeblock} +struct S { static constexpr int a = 1; }; +template struct TCls { static constexpr int b = 2; }; + +constexpr int c = [:^^S:]::a; // OK, \tcode{[:\caret\caret S:]} is not an expression +constexpr int d = template [:^^TCls:]::b; // OK, \tcode{template [:\caret\caret TCls:]} is not an expression +template constexpr int e = [:V:]; // OK +constexpr int f = template [:^^e:]<^^S::a>; // OK + +constexpr auto g = typename [:^^int:](42); // OK, \tcode{typename [:\caret\caret int:]} is a \grammarterm{splice-type-specifier} + +constexpr auto h = ^^g; +constexpr auto i = e<[:^^h:]>; // error: unparenthesized \grammarterm{splice-expression} used as template argument +constexpr auto j = e<([:^^h:])>; // OK +\end{codeblock} +\end{example} + +\pnum +For a \grammarterm{splice-expression} of the form \grammarterm{splice-specifier}, +let $S$ be the construct designated by \grammarterm{splice-specifier}. +\begin{itemize} +\item +The expression is ill-formed if $S$ is +\begin{itemize} +\item +a constructor, +\item +a destructor, +\item +an unnamed bit-field, or +\item +a local entity\iref{basic.pre} such that +\begin{itemize} +\item +there is a lambda scope that intervenes +between the expression and the point at which $S$ was introduced and +\item +the expression would be potentially evaluated +if the effect of any enclosing \keyword{typeid} expressions\iref{expr.typeid} +were ignored. +\end{itemize} +\end{itemize} +\item +Otherwise, if $S$ is a function $F$, +the expression denotes an overload set containing all declarations of $F$ +that precede either the expression or +the point immediately following the \grammarterm{class-specifier} of +the outermost class for which the expression is in a complete-class context; +overload resolution is performed\iref{over.match,over.over}. +\item +Otherwise, if $S$ is an object or a non-static data member, +the expression is an lvalue designating $S$. +The expression has the same type as that of $S$, and +is a bit-field if and only if $S$ is a bit-field. +\begin{note} +The implicit transformation +whereby an \grammarterm{id-expression} denoting a non-static member +becomes a class member access\iref{expr.prim.id} +does not apply to a \grammarterm{splice-expression}. +\end{note} +\item +Otherwise, if $S$ is a variable or a structured binding, +$S$ shall either have static or thread storage duration or +shall inhabit a scope enclosing the expression. +The expression is an lvalue referring to the object or function $X$ +associated with or referenced by $S$, +has the same type as that of $S$, and +is a bit-field if and only if $X$ is a bit-field. +\begin{note} +The type of a \grammarterm{splice-expression} +designating a variable or structured binding of reference type +will be adjusted to a non-reference type\iref{expr.type}. +\end{note} +\item +Otherwise, if $S$ is a value or an enumerator, +the expression is a prvalue that computes $S$ and +whose type is the same as that of $S$. +\item +Otherwise, the expression is ill-formed. +\end{itemize} + +\pnum +For a \grammarterm{splice-expression} of +the form \tcode{\keyword{template} \grammarterm{splice-specifier}}, +the \grammarterm{splice-specifier} shall designate a function template $T$ +that is not a constructor template. +The expression denotes an overload set containing all declarations of $T$ +that precede either the expression or +the point immediately following the \grammarterm{class-specifier} of +the outermost class for which the expression is in a complete-class context; +overload resolution is performed. +\begin{note} +During overload resolution, +candidate function templates undergo template argument deduction and +the resulting specializations are considered as candidate functions. +\end{note} + +\pnum +For a \grammarterm{splice-expression} of +the form \tcode{template \grammarterm{splice-specialization-specifier}}, +the \grammarterm{splice-specifier} of +the \grammarterm{splice-specialization-specifier} +shall designate a template $T$. +\begin{itemize} +\item +If $T$ is a function template, +the expression denotes an overload set containing all declarations of $T$ +that precede either the expression or +the point immediately following the \grammarterm{class-specifier} of +the outermost class for which the expression is in a complete-class context; +overload resolution is performed\iref{over.match,over.over}. +\item +Otherwise, if $T$ is a variable template, +let $S$ be the specialization of $T$ corresponding to +the template argument list of the \grammarterm{splice-specialization-specifier}. +The expression is an lvalue referring to +the object associated with $S$ and has the same type as that of $S$. +\item +Otherwise, the expression is ill-formed. +\end{itemize} +\begin{note} +Class members are accessible from any point +when designated by \grammarterm{splice-expression}s\iref{class.access.base}. +A class member access expression\iref{expr.ref} +whose right operand is a \grammarterm{splice-expression} is ill-formed +if the left operand (considered as a pointer) cannot be implicitly converted +to a pointer to the designating class of the right operand. +\end{note} + \rSec1[expr.compound]{Compound expressions} \rSec2[expr.post]{Postfix expressions}% @@ -3446,7 +3677,9 @@ simple-type-specifier braced-init-list\br typename-specifier braced-init-list\br postfix-expression \terminal{.} \opt{\keyword{template}} id-expression\br + postfix-expression \terminal{.} splice-expression\br postfix-expression \terminal{->} \opt{\keyword{template}} id-expression\br + postfix-expression \terminal{->} splice-expression\br postfix-expression \terminal{++}\br postfix-expression \terminal{--}\br \keyword{dynamic_cast} \terminal{<} type-id \terminal{>} \terminal{(} expression \terminal{)}\br @@ -3915,10 +4148,12 @@ A postfix expression followed by a dot \tcode{.} or an arrow \tcode{->}, optionally followed by the keyword \keyword{template}, and then followed by an -\grammarterm{id-expression}, is a postfix expression. +\grammarterm{id-expression} or a \grammarterm{splice-expression}, +is a postfix expression. \begin{note} -If the keyword \keyword{template} is used, -the following unqualified name +If the keyword \keyword{template} is used and +followed by an \grammarterm{id-expression}, +the unqualified name is considered to refer to a template\iref{temp.names}. If a \grammarterm{simple-template-id} results and is followed by a \tcode{::}, the \grammarterm{id-expression} is a \grammarterm{qualified-id}. @@ -3926,16 +4161,16 @@ \pnum \indextext{type!incomplete}% -For the first option (dot), -if the \grammarterm{id-expression} names a static member or an enumerator, +For a dot that is followed by an expression +that designates a static member or an enumerator, the first expression is a discarded-value expression\iref{expr.context}; -if the \grammarterm{id-expression} names a non-static data member, +if the expression after the dot designates a non-static data member, the first expression shall be a glvalue. -For the second option (arrow), the first expression +A postfix expression that is followed by an arrow shall be a prvalue having pointer type. The expression \tcode{E1->E2} is converted to the equivalent form \tcode{(*(E1)).E2}; the remainder of -\ref{expr.ref}~will address only the first option (dot). +\ref{expr.ref}~will address only the form using a dot. \begin{footnote} Note that \tcode{(*(E1))} is an lvalue. @@ -3951,12 +4186,14 @@ \grammarterm{id-expression} denotes a static member. \end{footnote} the result of that evaluation, -together with the \grammarterm{id-expression}, +together with +the \grammarterm{id-expression} or \grammarterm{splice-expression}, determines the result of the entire postfix expression. \pnum Abbreviating -\grammarterm{postfix-expression}\tcode{.}\grammarterm{id-expression} +\grammarterm{postfix-expression}\tcode{.}\grammarterm{id-expression} or +\grammarterm{postfix-expression}\tcode{.}\grammarterm{splice-expression} as \tcode{E1.E2}, \tcode{E1} is called the \defn{object expression}. If the object expression is of scalar type, \tcode{E2} shall name the pseudo-destructor @@ -3981,7 +4218,11 @@ \end{note} \pnum -If \tcode{E2} is a bit-field, \tcode{E1.E2} is a bit-field. The +If \tcode{E2} is a \grammarterm{splice-expression}, +then \tcode{E2} shall designate a member of the type of \tcode{E1}. + +\pnum +If \tcode{E2} designates a bit-field, \tcode{E1.E2} is a bit-field. The type and value category of \tcode{E1.E2} are determined as follows. In the remainder of~\ref{expr.ref}, \cvqual{cq} represents either \keyword{const} or the absence of \keyword{const} and \cvqual{vq} represents @@ -3990,9 +4231,10 @@ in~\ref{basic.type.qualifier}. \pnum -If \tcode{E2} is declared to have type ``reference to \tcode{T}'', then +If \tcode{E2} designates an entity +that is declared to have type ``reference to \tcode{T}'', then \tcode{E1.E2} is an lvalue of type \tcode{T}. -If \tcode{E2} is a static data member, +In that case, if \tcode{E2} designates a static data member, \tcode{E1.E2} designates the object or function to which the reference is bound, otherwise \tcode{E1.E2} designates the object or function to which @@ -4000,11 +4242,11 @@ Otherwise, one of the following rules applies. \begin{itemize} -\item If \tcode{E2} is a static data member and the type of \tcode{E2} +\item If \tcode{E2} designates a static data member and the type of \tcode{E2} is \tcode{T}, then \tcode{E1.E2} is an lvalue; the expression designates the named member of the class. The type of \tcode{E1.E2} is \tcode{T}. -\item If \tcode{E2} is a non-static data member and the type of +\item Otherwise, if \tcode{E2} designates a non-static data member and the type of \tcode{E1} is ``\cvqual{cq1 vq1} \tcode{X}'', and the type of \tcode{E2} is ``\cvqual{cq2 vq2} \tcode{T}'', the expression designates the corresponding member subobject of the object designated by the first expression. If \tcode{E1} @@ -4015,13 +4257,15 @@ is \tcode{volatile}, then \cvqual{vq12} is \keyword{volatile}. Similarly, let the notation \cvqual{cq12} stand for the ``union'' of \cvqual{cq1} and \cvqual{cq2}; that is, if \cvqual{cq1} or \cvqual{cq2} is -\keyword{const}, then \cvqual{cq12} is \keyword{const}. If \tcode{E2} is -declared to be a \keyword{mutable} member, then the type of \tcode{E1.E2} -is ``\cvqual{vq12} \tcode{T}''. If \tcode{E2} is not declared to be a -\keyword{mutable} member, then the type of \tcode{E1.E2} is -``\cvqual{cq12} \cvqual{vq12} \tcode{T}''. - -\item If \tcode{E2} is an overload set, +\keyword{const}, then \cvqual{cq12} is \keyword{const}. +If the entity designated by \tcode{E2} +is declared to be a \keyword{mutable} member, +then the type of \tcode{E1.E2} is ``\cvqual{vq12} \tcode{T}''. +If the entity designated by \tcode{E2} +is not declared to be a \keyword{mutable} member, +then the type of \tcode{E1.E2} is ``\cvqual{cq12} \cvqual{vq12} \tcode{T}''. + +\item If \tcode{E2} denotes an overload set, the expression shall be the (possibly-parenthesized) left-hand operand of a member function call\iref{expr.call}, and function overload resolution\iref{over.match} @@ -4041,26 +4285,30 @@ \end{note} \end{itemize} -\item If \tcode{E2} is a nested type, the expression \tcode{E1.E2} is +\item If \tcode{E2} designates a nested type, the expression \tcode{E1.E2} is ill-formed. -\item If \tcode{E2} is a member enumerator and the type of \tcode{E2} +\item If \tcode{E2} designates a member enumerator and the type of \tcode{E2} is \tcode{T}, the expression \tcode{E1.E2} is a prvalue of type \tcode{T} whose value is the value of the enumerator. + +\item Otherwise, the program is ill-formed. \end{itemize} \pnum -If \tcode{E2} is a non-static member, -the program is ill-formed if the class of which \tcode{E2} is -directly a member is an ambiguous base\iref{class.member.lookup} of -the naming class\iref{class.access.base} of \tcode{E2}. +If \tcode{E2} designates a non-static member +(possibly after overload resolution), +the program is ill-formed if the class of which \tcode{E2} designates +a direct member is an ambiguous base\iref{class.member.lookup} of +the designating class\iref{class.access.base} of \tcode{E2}. \begin{note} The program is also ill-formed if the naming class is an ambiguous base of the class type of the object expression; see~\ref{class.access.base}. \end{note} \pnum -If \tcode{E2} is a non-static member and +If \tcode{E2} designates a non-static member +(possibly after overload resolution) and the result of \tcode{E1} is an object whose type is not similar\iref{conv.qual} to the type of \tcode{E1}, the behavior is undefined. @@ -4907,7 +5155,8 @@ \keyword{alignof} \terminal{(} type-id \terminal{)}\br noexcept-expression\br new-expression\br - delete-expression + delete-expression\br + reflect-expression \end{bnf} \indextext{operator!indirection}% @@ -4963,14 +5212,25 @@ shall be an lvalue of some type \tcode{T}. \begin{itemize} \item -If the operand is a \grammarterm{qualified-id} naming a non-static or variant member \tcode{m} -of some class \tcode{C}, other than an explicit object member function, the result has type ``pointer to member -of class \tcode{C} of type \tcode{T}'' and designates \tcode{C::m}. +If the operand is a \grammarterm{qualified-id} or \grammarterm{splice-expression} +designating a non-static member \tcode{m}, +other than an explicit object member function, +\tcode{m} shall be a direct member of some class \tcode{C} +that is not an anonymous union. +The result has type ``pointer to member of class \tcode{C} of type \tcode{T}'' +and designates \tcode{C::m}. +\begin{note} +A \grammarterm{qualified-id} +that names a member of a namespace-scope anonymous union +is considered to be a class member access expression\iref{expr.prim.id.general} +and cannot be used to form a pointer to member. +\end{note} \item Otherwise, the result has type ``pointer to \tcode{T}'' and points to the designated object\iref{intro.memory} or function\iref{basic.compound}. -If the operand names an explicit object member function\iref{dcl.fct}, -the operand shall be a \grammarterm{qualified-id}. +If the operand designates an explicit object member function\iref{dcl.fct}, +the operand shall be +a \grammarterm{qualified-id} or a \grammarterm{splice-expression}. \begin{note} In particular, taking the address of a variable of type ``\cv{}~\tcode{T}'' yields a pointer of type ``pointer to \cv{}~\tcode{T}''. @@ -4995,8 +5255,9 @@ \pnum A pointer to member is only formed when an explicit \tcode{\&} is used -and its operand is a \grammarterm{qualified-id} not enclosed in -parentheses. +and its operand is +a \grammarterm{qualified-id} or \grammarterm{splice-expression} +not enclosed in parentheses. \begin{note} That is, the expression \tcode{\&(qualified-id)}, where the \grammarterm{qualified-id} is enclosed in parentheses, does not form an @@ -6327,6 +6588,232 @@ the behavior is undefined\iref{new.delete.single,new.delete.array}. \end{note} +\rSec3[expr.reflect]{The reflection operator} + +\begin{bnf} +\nontermdef{reflect-expression}\br + \terminal{\caret\caret} \terminal{::}\br + \terminal{\caret\caret} reflection-name\br + \terminal{\caret\caret} type-id\br + \terminal{\caret\caret} id-expression +\end{bnf} + +\begin{bnf} +\nontermdef{reflection-name}\br + \opt{nested-name-specifier} identifier\br + nested-name-specifier \keyword{template} identifier +\end{bnf} + +\pnum +The unary \tcode{\caret\caret} operator, +called the \defnadj{reflection}{operator}, +yields a prvalue of type \tcode{std::meta::info}\iref{basic.fundamental}. +\begin{note} +This document places no restriction on representing, by reflections, +constructs not described by this document or +using the names of such constructs +as operands of \grammarterm{reflect-expression}s. +\end{note} + +\pnum +The component names of a \grammarterm{reflection-name} +are those of its \grammarterm{nested-name-specifier} (if any) and +its \grammarterm{identifier}. +The terminal name of a \grammarterm{reflection-name} of the form +\grammarterm{nested-name-specifier} \keyword{template} \grammarterm{identifier} +shall denote a template. + +\pnum +A \grammarterm{reflect-expression} is parsed as +the longest possible sequence of tokens +that could syntactically form a \grammarterm{reflect-expression}. +An unparenthesized \grammarterm{reflect-expression} +that represents a template shall not be followed by \tcode{<}. +\begin{example} +\begin{codeblock} +static_assert(std::meta::is_type(^^int())); // \tcode{\caret\caret} applies to the type-id \tcode{int()} + +templatestruct X {}; +consteval bool operator<(std::meta::info, X) { return false; } +consteval void g(std::meta::info r, X xv) { + r == ^^int && true; // error: \tcode{\caret\caret} applies to the \grammarterm{type-id} \tcode{int\&\&} + r == ^^int & true; // error: \tcode{\caret\caret} applies to the type-id \tcode{int\&} + r == (^^int) && true; // OK + r == ^^int &&&& true; // error: \tcode{int \&\&\&\&} is not a valid \grammarterm{type-id} + ^^X < xv; // error: \grammarterm{reflect-expression} that represents a template is followed by \tcode{<} + (^^X) < xv; // OK + ^^X < xv; // OK +} +\end{codeblock} +\end{example} + +\pnum +A \grammarterm{reflect-expression} of the form \tcode{\caret\caret ::} +represents the global namespace. + +\pnum +If a \grammarterm{reflect-expression} $R$ matches +the form \tcode{\caret\caret \grammarterm{reflection-name}}, +it is interpreted as such; +the identifier is looked up and +the representation of $R$ is determined as follows: +\begin{itemize} +\item +If lookup finds a declaration +that replaced a \grammarterm{using-declarator} +during a single search\iref{basic.lookup.general,namespace.udecl}, +$R$ is ill-formed. +\begin{example} +\begin{codeblock} +struct A { struct S {}; }; +struct B : A { using A::S; }; +constexpr std::meta::info r1 = ^^B::S; // error: \tcode{A::S} found through \grammarterm{using-declarator} + +struct C : virtual B { struct S {}; }; +struct D : virtual B, C {}; +D::S s; // OK, names \tcode{C::S} per \ref{class.member.lookup} +constexpr std::meta::info r2 = ^^D::S; // OK, result \tcode{C::S} not found through \grammarterm{using-declarator} +\end{codeblock} +\end{example} +\item +Otherwise, if lookup finds a namespace alias\iref{namespace.alias}, +$R$ represents that namespace alias. +For any other \grammarterm{namespace-name}, +$R$ represents the denoted namespace. +\item +Otherwise, if lookup finds a namespace\iref{namespace.alias}, +$R$ represents that namespace. +\item +Otherwise, if lookup finds a concept\iref{temp.concept}, +$R$ represents the denoted concept. +\item +Otherwise, if lookup finds a template\iref{temp.names}, +the representation of $R$ is determined as follows: +\begin{itemize} +\item +If lookup finds an injected-class-name\iref{class.pre}, then: +\begin{itemize} +\item +If the \grammarterm{reflection-name} is of the form +\tcode{\grammarterm{nested-name-specifier} \keyword{template} \grammarterm{identifier}}, +then $R$ represents the class template named by the injected-class-name. +\item +Otherwise, the injected-class-name shall be unambiguous +when considered as a \grammarterm{type-name} and +$R$ represents the class template specialization so named. +\end{itemize} +\item +Otherwise, if lookup finds an overload set, +that overload set shall contain only +declarations of a unique function template F; +$R$ represents F. +\item +Otherwise, if lookup finds +a class template, variable template, or alias template, +$R$ represents that template. +\begin{note} +Lookup never finds a partial or explicit specialization. +\end{note} +\end{itemize} +\item +Otherwise, if lookup finds a type alias $A$, +$R$ represents the underlying entity of $A$ +if $A$ was introduced by the declaration of a template parameter; +otherwise, $R$ represents $A$. +\item +Otherwise, if lookup finds a class or an enumeration, +$R$ represents the denoted type. +\item +Otherwise, if lookup finds a class member of an anonymous union\iref{class.union.anon}, $R$ represents that class member. +\item +Otherwise, +the \grammarterm{reflection-name} shall be an \grammarterm{id-expression} \tcode{I} +and $R$ is \tcode{\caret\caret I} (see below). +\end{itemize} + +\pnum +A \grammarterm{reflect-expression} $R$ of the form +\tcode{\caret\caret \grammarterm{type-id}} +represents an entity determined as follows: +\begin{itemize} +\item +If the \grammarterm{type-id} designates +a placeholder type\iref{dcl.spec.auto.general}, +$R$ is ill-formed. +\item +Otherwise, if the \grammarterm{type-id} names a type alias +that is a specialization of an alias template\iref{temp.alias}, +$R$ represents that type alias. +\item +Otherwise, $R$ represents the type denoted by the \grammarterm{type-id}. +\end{itemize} + +\pnum +A \grammarterm{reflect-expression} $R$ of the form +\tcode{\caret\caret \grammarterm{id-expression}} +represents an entity determined as follows: +\begin{itemize} +\item +If the \grammarterm{id-expression} denotes +\begin{itemize} +\item +a variable declared by +an \grammarterm{init-capture}\iref{expr.prim.lambda.capture}, +\item +a function-local predefined variable\iref{dcl.fct.def.general}, +\item +a local parameter introduced by +a \grammarterm{requires-expression}\iref{expr.prim.req}, or +\item +a local entity $E$\iref{basic.pre} for which a lambda scope intervenes +between the point at which $E$ was introduced and $R$, +then $R$ is ill-formed. +\end{itemize} +\item +Otherwise, if the \grammarterm{id-expression} denotes an overload set $S$, +overload resolution for the expression \tcode{\&S} with no target +shall select a unique function\iref{over.over}; +$R$ represents that function. +\item +Otherwise, if the \grammarterm{id-expression} denotes +a variable, structured binding, enumerator, or non-static data member, +$R$ represents that entity. +\item +Otherwise, $R$ is ill-formed. +\begin{note} +This includes \grammarterm{unqualified-id}s +that name a constant template parameter and +\grammarterm{pack-index-expression}s. +\end{note} +\end{itemize} +The \grammarterm{id-expression} of +a \grammarterm{reflect-expression} is an unevaluated operand\iref{expr.context}. +\begin{example} +\begin{codeblock} +template void fn() requires (^^T != ^^int); +template void fn() requires (^^T == ^^int); +template void fn() requires (sizeof(T) == sizeof(int)); + +constexpr std::meta::info a = ^^fn; // OK +constexpr std::meta::info b = ^^fn; // error: ambiguous + +constexpr std::meta::info c = ^^std::vector; // OK + +template +struct S { + static constexpr std::meta::info r = ^^T; + using type = T; +}; +static_assert(S::r == ^^int); +static_assert(^^S::type != ^^int); + +typedef struct X {} Y; +typedef struct Z {} Z; +constexpr std::meta::info e = ^^Y; // OK, represents the type alias \tcode{Y} +constexpr std::meta::info f = ^^Z; // OK, represents the type alias \tcode{Z}, not the type\iref{basic.lookup.general} +\end{codeblock} +\end{example} + \rSec2[expr.cast]{Explicit type conversion (cast notation)}% \indextext{expression!cast|(} @@ -7113,6 +7600,20 @@ Two operands of type \tcode{std::nullptr_t} or one operand of type \tcode{std::nullptr_t} and the other a null pointer constant compare equal. +\pnum +If both operands are of type \tcode{std::meta::info}, +they compare equal if both operands +\begin{itemize} +\item are null reflection values, +\item represent values that are template-argument-equivalent\iref{temp.type}, +\item represent the same object, +\item represent the same entity, +\item represent the same annotation\iref{dcl.attr.annotation}, +\item represent the same direct base class relationship, or +\item represent equal data member descriptions\iref{class.mem.general}, +\end{itemize} +and they compare unequal otherwise. + \pnum If two operands compare equal, the result is \keyword{true} for the \tcode{==} operator and \keyword{false} for the \tcode{!=} operator. If two operands @@ -8158,6 +8659,11 @@ that would throw an exception where no definition of the exception type is reachable; +\item +an expression that would produce an injected declaration (see below), +unless $E$ is the corresponding expression of +a \grammarterm{consteval-block-declaration}\iref{dcl.pre}; + \item an \grammarterm{asm-declaration}\iref{dcl.asm}; @@ -8295,7 +8801,8 @@ \pnum During the evaluation of an expression $E$ as a core constant expression, -all \grammarterm{id-expression}s and uses of \tcode{*\keyword{this}} +all \grammarterm{id-expression}s, \grammarterm{splice-expression}s, and +uses of \tcode{*\keyword{this}} that refer to an object or reference whose lifetime did not begin with the evaluation of $E$ are treated as referring to a specific instance of that object or reference @@ -8448,8 +8955,30 @@ \pnum A \defnadj{constant}{expression} is either -a glvalue core constant expression that refers to -an object or a non-immediate function, or +\begin{itemize} +\item +a glvalue core constant expression $E$ for which +\begin{itemize} +\item +$E$ refers to a non-immediate function +\item +$E$ designates an object \tcode{o}, and +if the complete object of \tcode{o} is of consteval-only type then so is $E$, +\begin{example} +\begin{codeblock} +struct Base { }; +struct Derived : Base { std::meta::info r; }; + +consteval const Base& fn(const Derived& derived) { return derived; } + +constexpr Derived obj{.r=^^::}; // OK +constexpr const Derived& d = obj; // OK +constexpr const Base& b = fn(obj); // error: not a constant expression because \tcode{Derived} is a consteval-only type but \tcode{Base} is not. +\end{codeblock} +\end{example} +\end{itemize} +or +\item a prvalue core constant expression whose result object\iref{basic.lval} satisfies the following constraints: \begin{itemize} @@ -8461,7 +8990,21 @@ no constituent value of pointer type is a pointer to an immediate function or an invalid pointer value\iref{basic.compound}, and \item -no constituent value of pointer-to-member type designates an immediate function. +no constituent value of pointer-to-member type designates an immediate function, and +\item +unless the value is of consteval-only type, +\begin{itemize} +\item +no constituent value of pointer-to-member type points to +a direct member of a consteval-only class type +\item +no constituent value of pointer type points to or past an object +whose complete object is of consteval-only type, and +\item +no constituent reference refers to an object +whose complete object is of consteval-only type. +\end{itemize} +\end{itemize} \end{itemize} \begin{note} A glvalue core constant expression @@ -8537,17 +9080,17 @@ \indexdefn{conversion!immediate-escalating}% \indexdefn{immediate-escalating!expression|see{expression, immediate-escalating}}% \indexdefn{immediate-escalating!conversion|see{conversion, immediate-escalating}}% -An expression or conversion is \defn{immediate-escalating} -if it is not initially in an immediate function context -and it is either +A potentially-evaluated expression or conversion is \defn{immediate-escalating} +if it is neither initially in an immediate function context +nor a subexpression of an immediate invocation, and \begin{itemize} \item -a potentially-evaluated \grammarterm{id-expression} -that denotes an immediate function -that is not a subexpression of an immediate invocation, or +it is an \grammarterm{id-expression} or \grammarterm{splice-expression} +that designates an immediate function, \item -an immediate invocation that is not a constant expression -and is not a subexpression of an immediate invocation. +it is an immediate invocation that is not a constant expression, or +\item +it is of consteval-only type\iref{basic.types.general}. \end{itemize} \pnum @@ -8568,14 +9111,18 @@ in an immediate-escalating function. \pnum -An \defnadj{immediate}{function} is a function or constructor that is +An \defnadj{immediate}{function} is a function or constructor that is either \begin{itemize} \item declared with the \keyword{consteval} specifier, or \item an immediate-escalating function \tcode{\placeholder{F}} -whose function body contains an immediate-escalating expression \tcode{\placeholder{E}} -such that \tcode{\placeholder{E}}'s innermost enclosing non-block scope +whose function body contains either +\begin{itemize} +\item an immediate-escalating expression or +\item a definition of a non-constexpr variable with consteval-only type +\end{itemize} +whose innermost enclosing non-block scope is \tcode{\placeholder{F}}'s function parameter scope. \begin{tailnote} Default member initializers used to initialize @@ -8649,7 +9196,6 @@ \end{codeblock} \end{example} - \pnum An expression or conversion is \defn{manifestly constant-evaluated} if it is: @@ -8697,6 +9243,143 @@ is evaluated even in an unevaluated operand\iref{term.unevaluated.operand}. \end{note} +\pnum +The evaluation of an expression can introduce +one or more \defnadjx{injected}{declarations}{declaration}. +The evaluation is said to \defn{produce} the declarations. +\begin{note} +An invocation of +the library function template \tcode{std::meta::define_aggregate} +produces an injected declaration\iref{meta.reflection.define.aggregate}. +\end{note} +Each such declaration has +\begin{itemize} +\item +an associated \defnadj{synthesized}{point}, +which follows the last non-synthesized program point +in the translation unit containing that declaration, and +\item +an associated \defnadj{characteristic}{sequence} of values. +\end{itemize} +\begin{note} +Special rules concerning reachability +apply to synthesized points\iref{module.reach}. +\end{note} +\begin{note} +The program is ill-formed +if injected declarations with different characteristic sequences +define the same entity in different translation units\iref{basic.def.odr}. +\end{note} + +\pnum +A member of an entity defined by an injected declaration +shall not have a name reserved to the implementation\iref{lex.name}; +no diagnostic is required. + +\pnum +Let $C$ be a \grammarterm{consteval-block-declaration}, +the evaluation of whose corresponding expression +produces an injected declaration for an entity $E$. +The program is ill-formed if either +\begin{itemize} +\item +$C$ is enclosed by a scope associated with $E$ or +\item +letting $P$ be a point whose immediate scope is that to which $E$ belongs, +there is a function parameter scope or class scope +that encloses exactly one of $C$ or $P$. +\end{itemize} +\begin{example} +\begin{codeblock} +struct S0 { + consteval { + std::meta::define_aggregate(^^S0, {}); // error: scope associated with S0 encloses the consteval block + } +}; + +struct S1; +consteval { std::meta::define_aggregate(^^S1, {}); } // OK + +template consteval void tfn1() { + std::meta::define_aggregate(R, {}); +} + +struct S2; +consteval { tfn1<^^S2>(); } // OK + +template consteval void tfn2() { + consteval { std::meta::define_aggregate(R, {}); } +} + +struct S3; +consteval { tfn2<^^S3>(); } + // error: function parameter scope of \tcode{tfn2<\caret\caret S3>} intervenes between the declaration of \tcode{S3} + // and the consteval block that produces the injected declaration + +template struct TCls { + struct S4; + static void sfn() requires ([] { + consteval { std::meta::define_aggregate(^^S4, {}); } + return true; + }()) { } +}; + +consteval { TCls::sfn(); } // error: \tcode{TCls::S4} is not enclosed by \grammarterm{requires-clause} lambda + +struct S5; +struct Cls { + consteval { std::meta::define_aggregate(^^S5, {}); } // error: \tcode{S5} is not enclosed by class \tcode{Cls} +}; + +struct S6; +consteval { // \#1 + struct S7; // local class + std::meta::define_aggregate(^^S7, {}); + // error: consteval block \#1 does not enclose itself, but encloses \tcode{S7} + consteval { // \#2 + std::meta::define_aggregate(^^S6, {}); + // error: consteval block \#1 encloses consteval block \#2 but not \tcode{S6} + std::meta::define_aggregate(^^S7, {}); // OK, consteval block \#1 encloses both \#2 and \tcode{S7} + } +} +\end{codeblock} +\end{example} + +\pnum +The \defn{evaluation context} is a set of program points +that determines the behavior of certain functions +used for reflection\iref{meta.reflection}. +During the evaluation $V$ of an expression $E$ as a core constant expression, +the evaluation context of an evaluation $X$\iref{intro.execution} +consists of the following points: +\begin{itemize} +\item +The program point $\textit{EVAL-PT}(L)$, +where $L$ is the point at which $E$ appears, and +where $\textit{EVAL-PT}(P)$, for a point $P$, +is a point $R$ determined as follows: +\begin{itemize} +\item +If a potentially-evaluated subexpression\iref{intro.execution} of +a default member initializer $I$ appears at $P$, and +a (possibly aggregate) initialization during $V$ is using $I$, +then $R$ is $\textit{EVAL-PT}(Q)$ +where $Q$ is the point at which that initialization appears. +\item +Otherwise, if a potentially-evaluated subexpression of +a default argument\iref{dcl.fct.default} appears at $P$, and +an invocation of a function\iref{expr.call} during $V$ +is using that default argument, +then $R$ is $\textit{EVAL-PT}(Q)$ +where $Q$ is the point at which that invocation appears. +\item +Otherwise, $R$ is $P$. +\end{itemize} +\item +Each synthesized point corresponding to an injected declaration produced by +any evaluation sequenced before $X$\iref{intro.execution}. +\end{itemize} + \pnum \indextext{expression!potentially constant evaluated}% An expression or conversion is \defn{potentially constant evaluated} diff --git a/source/lex.tex b/source/lex.tex index eb4f060959..4cc651a14d 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -210,43 +210,84 @@ only, and does not specify any particular implementation. \end{note} -\item Translated translation units and instantiation units are combined -as follows: -\begin{note} -Some or all of these can be supplied from a -library. -\end{note} -Each translated translation unit is examined to -produce a list of required instantiations. +While the tokens constituting translation units +are being analyzed and translated, +required instantiations are performed. \begin{note} This can include instantiations which have been explicitly requested\iref{temp.explicit}. \end{note} -The definitions of the -required templates are located. It is \impldef{whether source of translation units must -be available to locate template definitions} whether the -source of the translation units containing these definitions is required -to be available. -\begin{note} -An implementation can choose to encode sufficient -information into the translated translation unit so as to ensure the -source is not required here. -\end{note} -All the required instantiations -are performed to produce -\defn{instantiation units}. + +The contexts from which instantiations may be performed +are determined by their respective points of instantiation\iref{temp.point}. + \begin{note} -These are similar -to translated translation units, but contain no references to -uninstantiated templates and no template definitions. +Other requirements in this document can further constrain +the context from which an instantiation can be performed. +For example, a constexpr function template specialization +might have a point of instantation at the end of a translation unit, +but its use in certain constant expressions could require +that it be instantiated at an earlier point\iref{temp.inst}. \end{note} -The -program is ill-formed if any instantiation fails. + +Each instantiation results in new program constructs. +The program is ill-formed if any instantiation fails. + +During the analysis and translation of tokens, +certain expressions are evaluated\iref{expr.const}. +Constructs appearing at a program point $P$ are analyzed +in a context where each side effect of evaluating an expression $E$ +as a full-expression is complete if and only if +\begin{itemize} +\item +$E$ is the expression corresponding to +a \grammarterm{consteval-block-declaration}\iref{dcl.pre}, and +\item +either that \grammarterm{consteval-block-declaration} or +the template definition from which it is instantiated +is reachable from\iref{module.reach} +\begin{itemize} +\item +$P$, or +\item +the point immediately following +the \grammarterm{class-specifier} of the outermost class +for which $P$ is in a complete-class context\iref{class.mem.general}. +\end{itemize} +\end{itemize} +\begin{example} +\begin{codeblock} +class S { + class Incomplete; + + class Inner { + void fn() { + /* P1 */ Incomplete i; // OK + } + }; /* P2 */ + + consteval { + define_aggregate(^^Incomplete, {}); + } +}; /* P3 */ +\end{codeblock} +Constructs at P1 are analyzed in a context +where the side effect of the call to \tcode{define_aggregate} is evaluated +because +\begin{itemize} +\item +$E$ is the expression corresponding to a consteval block, and +\item +P1 is in a complete-class context of \tcode{S} and +the consteval block is reachable from P3. +\end{itemize} +\end{example} \item \indextext{linking}% -All external entity references are resolved. Library +Translated translation units are combined, and +all external entity references are resolved. Library components are linked to satisfy external references to entities not defined in the current translation. All such translator output is collected into a program image which contains information @@ -584,6 +625,16 @@ is neither \tcode{:} nor \tcode{>}, the \tcode{<} is treated as a preprocessing token by itself and not as the first character of the alternative token \tcode{<:}. +\item +Otherwise, if the next three characters are \tcode{[::} and +the subsequent character is not \tcode{:}, or +if the next three characters are \tcode{[:>}, +the \tcode{[} is treated as a preprocessing token by itself and +not as the first character of the preprocessing token \tcode{[:}. +\begin{note} +The tokens \tcode{[:} and \tcode{:]} cannot be composed from digraphs. +\end{note} + \item Otherwise, the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token, even if that @@ -750,9 +801,9 @@ \begin{bnf} \microtypesetup{protrusion=false} \nontermdef{operator-or-punctuator} \textnormal{one of}\br - \terminal{\{ \ \ \ \ \ \ \ \} \ \ \ \ \ \ \ [ \ \ \ \ \ \ \ ] \ \ \ \ \ \ \ ( \ \ \ \ \ \ \ )}\br + \terminal{\{ \ \ \ \ \ \ \ \} \ \ \ \ \ \ \ [ \ \ \ \ \ \ \ ] \ \ \ \ \ \ \ ( \ \ \ \ \ \ \ ) \ \ \ \ \ \ \ [: \ \ \ \ \ \ :]}\br \terminal{<\% \ \ \ \ \ \ \%> \ \ \ \ \ \ <: \ \ \ \ \ \ :> \ \ \ \ \ \ ; \ \ \ \ \ \ \ : \ \ \ \ \ \ \ ...}\br - \terminal{? \ \ \ \ \ \ \ :: \ \ \ \ \ \ . \ \ \ \ \ \ \ .* \ \ \ \ \ \ -> \ \ \ \ \ \ ->* \ \ \ \ \ \~}\br + \terminal{? \ \ \ \ \ \ \ :: \ \ \ \ \ \ . \ \ \ \ \ \ \ .* \ \ \ \ \ \ -> \ \ \ \ \ \ ->* \ \ \ \ \ \caret{}\caret{} \ \ \ \ \ \ \~}\br \terminal{! \ \ \ \ \ \ \ + \ \ \ \ \ \ \ - \ \ \ \ \ \ \ * \ \ \ \ \ \ \ / \ \ \ \ \ \ \ \% \ \ \ \ \ \ \ \caret{} \ \ \ \ \ \ \ \& \ \ \ \ \ \ \ |}\br \terminal{= \ \ \ \ \ \ \ += \ \ \ \ \ \ -= \ \ \ \ \ \ *= \ \ \ \ \ \ /= \ \ \ \ \ \ \%= \ \ \ \ \ \ \caret{}= \ \ \ \ \ \ \&= \ \ \ \ \ \ |=}\br \terminal{== \ \ \ \ \ \ != \ \ \ \ \ \ < \ \ \ \ \ \ \ > \ \ \ \ \ \ \ <= \ \ \ \ \ \ >= \ \ \ \ \ \ <=> \ \ \ \ \ \&\& \ \ \ \ \ \ ||}\br diff --git a/source/lib-intro.tex b/source/lib-intro.tex index ea7a21b782..4816083dd2 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -368,6 +368,11 @@ and also define the function as deleted. \end{example} +\item +\constantwhen +the conditions that are required for a call to the function +to be a constant subexpression\iref{defns.const.subexpr}. + \item \expects conditions that the function assumes to hold whenever it is called; @@ -454,6 +459,7 @@ Next, the semantics of the code sequence are determined by the \Fundescx{Constraints}, \Fundescx{Mandates}, +\Fundescx{Constant When}, \Fundescx{Preconditions}, \Fundescx{Hardened preconditions}, \Fundescx{Effects}, @@ -1223,8 +1229,8 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ -\tcode{} \\ \columnbreak +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1248,8 +1254,9 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ -\tcode{} \\ \columnbreak +\tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1271,9 +1278,9 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\columnbreak \tcode{} \\ \tcode{} \\ -\columnbreak \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -3082,6 +3089,26 @@ either a standard library non-static member function\iref{member.functions} or an instantiation of a standard library member function template. +\pnum +Let \tcode{\placeholder{F}} denote +a standard library function or function template. +Unless \tcode{\placeholder{F}} is designated an addressable function, +it is unspecified if or how +a reflection value designating the associated entity can be formed. +%FIXME: Why is this not an example, but a note that begins with "For example"? +\begin{note} +For example, it is possible that \tcode{std::meta::members_of} +will not return reflections of standard library functions +that an implementation handles through an extra-linguistic mechanism. +\end{note} + +\pnum +Let \tcode{\placeholder{F}} denote +a standard library class or class template specialization. +It is unspecified if or how +a reflection value can be formed to any private member of \tcode{\placeholder{F}}, +or what the names of such members may be. + \pnum A translation unit shall not declare namespace \tcode{std} to be an inline namespace\iref{namespace.def}. diff --git a/source/macros.tex b/source/macros.tex index ec88684fcd..918bfdf3a5 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -363,6 +363,7 @@ \newcommand{\required}{\Fundesc{Required behavior}} \newcommand{\constraints}{\Fundesc{Constraints}} \newcommand{\mandates}{\Fundesc{Mandates}} +\newcommand{\constantwhen}{\Fundesc{Constant When}} \newcommand{\expects}{\Fundesc{Preconditions}} \newcommand{\hardexpects}{\Fundesc{Hardened preconditions}} \newcommand{\effects}{\Fundesc{Effects}} @@ -465,6 +466,10 @@ \newcommand{\unspecuniqtype}{\UNSP{unspecified unique type}} \newcommand{\unspecalloctype}{\UNSP{unspecified allocator type}} +%% Convenience macro for double carets in expressions, +%% particularly within \tcode. +\newcommand{\reflexpr}[1]{\caret\caret#1} + %% Manual insertion of italic corrections, for aligning in the presence %% of the above annotations. \newlength{\itcorrwidth} diff --git a/source/meta.tex b/source/meta.tex index cb8e6e7ade..43c1894699 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -179,6 +179,7 @@ template struct is_union; template struct is_class; template struct is_function; + template struct is_reflection; // \ref{meta.unary.comp}, composite type categories template struct is_reference; @@ -201,6 +202,7 @@ template struct is_abstract; template struct is_final; template struct is_aggregate; + template struct is_consteval_only; template struct is_signed; template struct is_unsigned; @@ -410,6 +412,8 @@ constexpr bool @\libglobal{is_class_v}@ = is_class::value; template constexpr bool @\libglobal{is_function_v}@ = is_function::value; + template + constexpr bool @\libglobal{is_reflection_v}@ = is_reflection::value; // \ref{meta.unary.comp}, composite type categories template @@ -448,6 +452,8 @@ constexpr bool @\libglobal{is_final_v}@ = is_final::value; template constexpr bool @\libglobal{is_aggregate_v}@ = is_aggregate::value; +template + constexpr bool @\libglobal{is_consteval_only_v}@ = is_consteval_only::value; template constexpr bool @\libglobal{is_signed_v}@ = is_signed::value; template @@ -723,7 +729,11 @@ \indexlibraryglobal{is_function}% \tcode{template}\br \tcode{struct is_function;} & -\tcode{T} is a function type\iref{basic.compound} & \\ +\tcode{T} is a function type\iref{basic.compound} & \\ \rowsep +\indexlibraryglobal{is_reflection}% +\tcode{template}\br + \tcode{struct is_reflection;} & +\tcode{T} is \tcode{std::meta::info} & \\ \end{libreqtab3e} \rSec3[meta.unary.comp]{Composite type traits} @@ -905,6 +915,12 @@ \tcode{T} is an aggregate type\iref{dcl.init.aggr} & \tcode{T} shall be an array type, a complete type, or \cv~\keyword{void}. \\ \rowsep +\indexlibraryglobal{is_consteval_only}% +\tcode{template}\br + \tcode{struct is_consteval_only;} & + \tcode{T} is consteval-only\iref{basic.types.general} & + \tcode{remove_all_extents_t} shall be a complete type or \cv~\keyword{void}. \\ \rowsep + \indexlibrary{\idxcode{is_signed}!class}% \tcode{template}\br \tcode{struct is_signed;} & @@ -2554,6 +2570,3514 @@ \end{example} \end{itemdescr} +\rSec1[meta.reflection]{Reflection} + +%FIXME: Jens said this should be [meta.syn] +\rSec2[meta.reflection.synop]{General} +\indexheader{meta}% + +\begin{codeblock} +#include // see \ref{initializer.list.syn} + +namespace std::meta { + using info = decltype(^^::); + + // \ref{meta.reflection.operators}, operator representations + enum class operators { + @\seebelow@; + }; + using enum operators; + consteval operators operator_of(info r); + consteval string_view symbol_of(operators op); + consteval u8string_view u8symbol_of(operators op); + + // \ref{meta.reflection.names}, reflection names and locations + consteval bool has_identifier(info r); + + consteval string_view identifier_of(info r); + consteval u8string_view u8identifier_of(info r); + + consteval string_view display_string_of(info r); + consteval u8string_view u8display_string_of(info r); + + consteval source_location source_location_of(info r); + + // \ref{meta.reflection.queries}, reflection queries + consteval info type_of(info r); + consteval info object_of(info r); + consteval info constant_of(info r); + + 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_annotation(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_c_language_linkage(info r); + consteval bool has_linkage(info r); + + consteval bool is_complete_type(info r); + consteval bool is_enumerable_type(info r); + + consteval bool is_variable(info r); + consteval bool is_type(info r); + consteval bool is_namespace(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 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 bool has_parent(info r); + consteval info parent_of(info r); + + consteval info dealias(info r); + + consteval bool has_template_arguments(info r); + consteval info template_of(info r); + consteval vector template_arguments_of(info r); + + // \ref{meta.reflection.access.context}, access control context + struct access_context; + + // \ref{meta.reflection.access.queries}, member accessessibility queries + consteval bool is_accessible(info r, access_context ctx); + consteval bool has_inaccessible_nonstatic_data_members(info r, access_context ctx); + consteval bool has_inaccessible_bases(info r, access_context ctx); + + // \ref{meta.reflection.member.queries}, reflection member queries + consteval vector members_of(info r, access_context ctx); + consteval vector bases_of(info type, access_context ctx); + consteval vector static_data_members_of(info type, access_context ctx); + consteval vector nonstatic_data_members_of(info type, access_context ctx); + consteval vector enumerators_of(info type_enum); + + // \ref{meta.reflection.layout}, reflection layout queries + struct member_offset; + 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); + + // \ref{meta.reflection.extract}, value extraction + template + consteval T extract(info); + + // \ref{meta.reflection.substitute}, reflection substitution + template + concept reflection_range = @\seebelow@; + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool can_substitute(info templ, R&& arguments); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info substitute(info templ, R&& arguments); + + // \ref{meta.reflection.result}, expression result reflection + template + consteval info reflect_constant(const T& value); + template + consteval info reflect_object(T& object); + template + consteval info reflect_function(T& fn); + + // \ref{meta.reflection.define.aggregate}, class definition generation + struct data_member_options; + consteval info data_member_spec(info type, data_member_options options); + consteval bool is_data_member_spec(info r); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info define_aggregate(info type_class, R&&); + + // associated with \ref{meta.unary.cat}, primary type categories + consteval bool is_void_type(info type); + consteval bool is_null_pointer_type(info type); + consteval bool is_integral_type(info type); + consteval bool is_floating_point_type(info type); + consteval bool is_array_type(info type); + consteval bool is_pointer_type(info type); + consteval bool is_lvalue_reference_type(info type); + consteval bool is_rvalue_reference_type(info type); + consteval bool is_member_object_pointer_type(info type); + consteval bool is_member_function_pointer_type(info type); + consteval bool is_enum_type(info type); + consteval bool is_union_type(info type); + consteval bool is_class_type(info type); + consteval bool is_function_type(info type); + consteval bool is_reflection_type(info type); + + // associated with \ref{meta.unary.comp}, composite type categories + consteval bool is_reference_type(info type); + consteval bool is_arithmetic_type(info type); + consteval bool is_fundamental_type(info type); + consteval bool is_object_type(info type); + consteval bool is_scalar_type(info type); + consteval bool is_compound_type(info type); + consteval bool is_member_pointer_type(info type); + + // associated with \ref{meta.unary.prop}, type properties + consteval bool is_const_type(info type); + consteval bool is_volatile_type(info type); + consteval bool is_trivially_copyable_type(info type); + consteval bool is_trivially_relocatable_type(info type); + consteval bool is_replaceable_type(info type); + consteval bool is_standard_layout_type(info type); + consteval bool is_empty_type(info type); + consteval bool is_polymorphic_type(info type); + consteval bool is_abstract_type(info type); + consteval bool is_final_type(info type); + consteval bool is_aggregate_type(info type); + consteval bool is_consteval_only_type(info type); + consteval bool is_signed_type(info type); + consteval bool is_unsigned_type(info type); + consteval bool is_bounded_array_type(info type); + consteval bool is_unbounded_array_type(info type); + consteval bool is_scoped_enum_type(info type); + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_constructible_type(info type, R&& type_args); + consteval bool is_default_constructible_type(info type); + consteval bool is_copy_constructible_type(info type); + consteval bool is_move_constructible_type(info type); + + consteval bool is_assignable_type(info type_dst, info type_src); + consteval bool is_copy_assignable_type(info type); + consteval bool is_move_assignable_type(info type); + + consteval bool is_swappable_with_type(info type_dst, info type_src); + consteval bool is_swappable_type(info type); + + consteval bool is_destructible_type(info type); + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_trivially_constructible_type(info type, R&& type_args); + consteval bool is_trivially_default_constructible_type(info type); + consteval bool is_trivially_copy_constructible_type(info type); + consteval bool is_trivially_move_constructible_type(info type); + + consteval bool is_trivially_assignable_type(info type_dst, info type_src); + consteval bool is_trivially_copy_assignable_type(info type); + consteval bool is_trivially_move_assignable_type(info type); + consteval bool is_trivially_destructible_type(info type); + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_nothrow_constructible_type(info type, R&& type_args); + consteval bool is_nothrow_default_constructible_type(info type); + consteval bool is_nothrow_copy_constructible_type(info type); + consteval bool is_nothrow_move_constructible_type(info type); + + consteval bool is_nothrow_assignable_type(info type_dst, info type_src); + consteval bool is_nothrow_copy_assignable_type(info type); + consteval bool is_nothrow_move_assignable_type(info type); + + consteval bool is_nothrow_swappable_with_type(info type_dst, info type_src); + consteval bool is_nothrow_swappable_type(info type); + + consteval bool is_nothrow_destructible_type(info type); + consteval bool is_nothrow_relocatable_type(info type); + + consteval bool is_implicit_lifetime_type(info type); + + consteval bool has_virtual_destructor(info type); + + consteval bool has_unique_object_representations(info type); + + consteval bool reference_constructs_from_temporary(info type_dst, info type_src); + consteval bool reference_converts_from_temporary(info type_dst, info type_src); + + // associated with \ref{meta.unary.prop.query}, type property queries + consteval size_t rank(info type); + consteval size_t extent(info type, unsigned i = 0); + + // associated with \ref{meta.rel}, type relations + consteval bool is_same_type(info type1, info type2); + consteval bool is_base_of_type(info type_base, info type_derived); + consteval bool is_virtual_base_of_type(info type_base, info type_derived); + consteval bool is_convertible_type(info type_src, info type_dst); + consteval bool is_nothrow_convertible_type(info type_src, info type_dst); + consteval bool is_layout_compatible_type(info type1, info type2); + consteval bool is_pointer_interconvertible_base_of_type(info type_base, info type_derived); + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_invocable_type(info type, R&& type_args); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_invocable_r_type(info type_result, info type, R&& type_args); + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_nothrow_invocable_type(info type, R&& type_args); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_nothrow_invocable_r_type(info type_result, info type, R&& type_args); + + // associated with \ref{meta.trans.cv}, const-volatile modifications + consteval info remove_const(info type); + consteval info remove_volatile(info type); + consteval info remove_cv(info type); + consteval info add_const(info type); + consteval info add_volatile(info type); + consteval info add_cv(info type); + + // associated with \ref{meta.trans.ref}, reference modifications + consteval info remove_reference(info type); + consteval info add_lvalue_reference(info type); + consteval info add_rvalue_reference(info type); + + // associated with \ref{meta.trans.sign}, sign modifications + consteval info make_signed(info type); + consteval info make_unsigned(info type); + + // associated with \ref{meta.trans.arr}, array modifications + consteval info remove_extent(info type); + consteval info remove_all_extents(info type); + + // associated with \ref{meta.trans.ptr}, pointer modifications + consteval info remove_pointer(info type); + consteval info add_pointer(info type); + + // associated with \ref{meta.trans.other}, other transformations + consteval info remove_cvref(info type); + consteval info decay(info type); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info common_type(R&& type_args); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info common_reference(R&& type_args); + consteval info type_underlying_type(info type); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info invoke_result(info type, R&& type_args); + consteval info unwrap_reference(info type); + consteval info unwrap_ref_decay(info type); + + consteval size_t tuple_size(info type); + consteval info tuple_element(size_t index, info type); + + consteval size_t variant_size(info type); + consteval info variant_alternative(size_t index, info type); + + consteval strong_ordering type_order(info type_a, info type_b); + + // \ref{meta.reflection.annotation}, annotation reflection + consteval vector annotations_of(info item); + consteval vector annotations_of_with_type(info item, info type); + +} +\end{codeblock} + +\pnum +Unless otherwise specified, +each function, and each specialization of any function template, +specified in this header +is a designated addressable function\iref{namespace.std}. + +\pnum +The behavior of any function specified in namespace \tcode{std::meta} is +\impldef{behavior of any function in \tcode{std::meta} +for implementation-specific constructs} +when a reflection of a construct not otherwise specified by this document +is provided as an argument. +\begin{note} +Values of type \tcode{std::meta::info} +can represent implementation-specific constructs\iref{basic.fundamental}. +\end{note} +\begin{note} +The behavior of many of the functions specified in namespace \tcode{std::meta} +have semantics that can be affected by +the completeness of class types represented by reflection values. +For such functions, +for any reflection \tcode{r} such that \tcode{dealias(r)} +represents a specialization of a templated class with a reachable definition, +the specialization is implicitly instantiated\iref{temp.inst}. +\begin{example} +\begin{codeblock} +template +struct X { + T mem; +}; + +static_assert(size_of(^^X) == sizeof(int)); // instantiates \tcode{X} +\end{codeblock} +\end{example} +\end{note} + +\pnum +Any function in namespace \tcode{std::meta} +whose return type is \tcode{string_view} or \tcode{u8string_view} +returns an object \exposid{V} such that +\tcode{\exposid{V}.data()[\exposid{V}.size()]} equals \tcode{'\textbackslash 0'}. +\begin{example} +\begin{codeblock} +struct C { }; + +constexpr string_view sv = identifier_of(^^C); +static_assert(sv == "C"); +static_assert(sv.data()[0] == 'C'); +%TODO: investigate if this is how we usually do backslashes in code blocks +static_assert(sv.data()[1] == '@\textbackslash@ 0'); +\end{codeblock} +\end{example} + +\rSec2[meta.reflection.operators]{Operator representations} + +\begin{itemdecl} +enum class @\libglobal{operators}@ { + @\seebelow@; +}; +using enum operators; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The enumeration type \tcode{operators} specifies +constants used to identify operators that can be overloaded, +with the meanings listed in~\tref{meta.reflection.operators}. +The values of the constants are distinct. +\end{itemdescr} + +%TODO: double-check if this is the right table environment for the job +%TODO: What is the best way to index these enum members? +\begin{floattable}{Enum class\tcode{operators}}{meta.reflection.operators} +{lcc} +\topline +\chdr{Constant} & +\chdr{Corresponding \grammarterm{operator-function-id}} & +\chdr{Operator symbol name} \\ \capsep +\tcode{op_new} & \tcode{operator new} & \tcode{new} \\ \rowsep +\tcode{op_delete} & \tcode{operator delete} & \tcode{delete} \\ \rowsep +\tcode{op_array_new} & \tcode{operator new[]} & \tcode{new[]} \\ \rowsep +\tcode{op_array_delete} & \tcode{operator delete[]} & \tcode{delete[]} \\ \rowsep +\tcode{op_co_await} & \tcode{operator co_await} & \tcode{co_await} \\ \rowsep +\tcode{op_parentheses} & \tcode{operator()} & \tcode{()} \\ \rowsep +\tcode{op_square_brackets} & \tcode{operator[]} & \tcode{[]} \\ \rowsep +\tcode{op_arrow} & \tcode{operator->} & \tcode{->} \\ \rowsep +\tcode{op_arrow_star} & \tcode{operator->*} & \tcode{->*} \\ \rowsep +\tcode{op_tilde} & \tcode{operator~} & \tcode{~} \\ \rowsep +\tcode{op_exclamation} & \tcode{operator!} & \tcode{!} \\ \rowsep +\tcode{op_plus} & \tcode{operator+} & \tcode{+} \\ \rowsep +\tcode{op_minus} & \tcode{operator-} & \tcode{-} \\ \rowsep +\tcode{op_star} & \tcode{operator*} & \tcode{*} \\ \rowsep +\tcode{op_slash} & \tcode{operator/} & \tcode{/} \\ \rowsep +\tcode{op_percent} & \tcode{operator\%} & \tcode{\%} \\ \rowsep +\tcode{op_caret} & \tcode{operator\caret} & \tcode{\caret} \\ \rowsep +\tcode{op_ampersand} & \tcode{operator\&} & \tcode{\&} \\ \rowsep +\tcode{op_equals} & \tcode{operator=} & \tcode{=} \\ \rowsep +\tcode{op_pipe} & \tcode{operator|} & \tcode{|} \\ \rowsep +\tcode{op_plus_equals} & \tcode{operator+=} & \tcode{+} \\ \rowsep +\tcode{op_minus_equals} & \tcode{operator-=} & \tcode{-} \\ \rowsep +\tcode{op_star_equals} & \tcode{operator*=} & \tcode{*} \\ \rowsep +\tcode{op_slash_equals} & \tcode{operator/=} & \tcode{/} \\ \rowsep +\tcode{op_percent_equals} & \tcode{operator\%=} & \tcode{\%} \\ \rowsep +\tcode{op_caret_equals} & \tcode{operator\caret=} & \tcode{\caret=} \\ \rowsep +\tcode{op_ampersand_equals} & \tcode{operator\&=} & \tcode{\&} \\ \rowsep +\tcode{op_pipe_equals} & \tcode{operator|=} & \tcode{|} \\ \rowsep +\tcode{op_equals_equals} & \tcode{operator==} & \tcode{==} \\ \rowsep +\tcode{op_exclamation_equals} & \tcode{operator!=} & \tcode{!=} \\ \rowsep +\tcode{op_less} & \tcode{operator<} & \tcode{<} \\ \rowsep +\tcode{op_greater} & \tcode{operator>} & \tcode{>} \\ \rowsep +\tcode{op_less_equals} & \tcode{operator<=} & \tcode{<=} \\ \rowsep +\tcode{op_greater_equals} & \tcode{operator>=} & \tcode{>=} \\ \rowsep +\tcode{op_spaceship} & \tcode{operator<=>} & \tcode{<=>} \\ \rowsep +\tcode{op_ampersand_ampersand} & \tcode{operator\&\&} & \tcode{\&\&} \\ \rowsep +\tcode{op_pipe_pipe} & \tcode{operator||} & \tcode{||} \\ \rowsep +\tcode{op_less_less} & \tcode{operator<<} & \tcode{<<} \\ \rowsep +\tcode{op_greater_greater} & \tcode{operator>>} & \tcode{>>} \\ \rowsep +\tcode{op_less_less_equals} & \tcode{operator<<=} & \tcode{<<=} \\ \rowsep +\tcode{op_greater_greater_equals} & \tcode{operator>>=} & \tcode{>>=} \\ \rowsep +\tcode{op_plus_plus} & \tcode{operator++} & \tcode{++} \\ \rowsep +\tcode{op_minus_minus} & \tcode{operator--} & \tcode{--} \\ \rowsep +\tcode{op_comma} & \tcode{operator,} & \tcode{,} \\ +\end{floattable} + +\indexlibraryglobal{operator_of}% +\begin{itemdecl} +consteval operators operator_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{r} represents an operator function or operator function template. + +\pnum +\returns +The value of the enumerator from the \tcode{operators} +whose corresponding \grammarterm{operator-function-id} +is the unqualified name of the entity represented by \tcode{r}. +\end{itemdescr} + +\indexlibraryglobal{symbol_of}% +\indexlibraryglobal{u8symbol_of}% +\begin{itemdecl} +consteval string_view symbol_of(operators op); +consteval u8string_view u8symbol_of(operators op); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +The value of \tcode{op} corresponds to one of the enumerators in \tcode{operators}. + +\pnum +\returns +A \tcode{string_view} or \tcode{u8string_view} +containing the characters of the operator symbol name corresponding to \tcode{op}, +respectively encoded with the ordinary literal encoding or with UTF-8. +\end{itemdescr} + +\rSec2[meta.reflection.names]{Reflection names and locations} + +\indexlibraryglobal{has_identifier}% +\begin{itemdecl} +consteval bool has_identifier(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents an entity + that has a typedef name for linkage purposes\iref{dcl.typedef}, + then \tcode{true}. +\item + Otherwise, if \tcode{r} represents an unnamed entity, + then \tcode{false}. +\item + Otherwise, if \tcode{r} represents a class type, + then \tcode{!has_template_arguments(r)}. +\item + Otherwise, if \tcode{r} represents a function, + then \tcode{true} if \tcode{has_template_arguments(r)} is \tcode{false} + and the function is not a + constructor, + destructor, + operator function, or + conversion function. + Otherwise, \tcode{false}. +\item + Otherwise, if \tcode{r} represents a template, + then \tcode{true} if \tcode{r} does not represent a + constructor template, + operator function template, + or conversion function template. + Otherwise, \tcode{false}. +\item + Otherwise, if \tcode{r} represents a variable, + then \tcode{false} if the declaration of that variable + was instantiated from a function parameter pack. + Otherwise, \tcode{!has_template_arguments(r)}. +\item + Otherwise, if \tcode{r} represents a structured binding, + then \tcode{false} if the declaration of that structured binding + was instantiated from a structured binding pack. + Otherwise, \tcode{true}. +\item + Otherwise, if \tcode{r} represents a type alias, + then \tcode{!has_template_arguments(s)}. +\item + Otherwise, if \tcode{r} represents an + enumerator, + non-static-data member, + namespace, or + namespace alias, + then \tcode{true}. +\item + Otherwise, if \tcode{r} represents a direct base class relationship, + then \tcode{has_identifier(type_of(r))}. +\item + Otherwise, \tcode{r} represents a data member description + $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general}; + \tcode{true} if $N$ is not $\perp$. + Otherwise, \tcode{false}. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{identifier_of}% +\indexlibraryglobal{u8identifier_of}% +\begin{itemdecl} +consteval string_view identifier_of(info r); +consteval u8string_view u8identifier_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $E$ be UTF-8 for \tcode{u8identifier_of}, +and otherwise the ordinary literal encoding. + +\pnum +\constantwhen +\tcode{has_identifier(r)} is \tcode{true} +and the identifier that would be returned (see below) +is representable by $E$. + +\pnum +\returns +An \ntmbs{}, encoded with $E$, +determined as follows: +\begin{itemize} +\item + If \tcode{r} represents an entity with a typedef name for linkage purposes, + then that name. +\item + Otherwise, if \tcode{r} represents a literal operator or literal operator template, + then the \grammarterm{ud-suffix} of the operator or operator template. +\item + Otherwise, if \tcode{r} represents an entity, + then the identifier introduced by the declaration of that entity. +\item + Otherwise, if \tcode{r} represents a direct base class relationship, + then \tcode{identifier_of(type_of(r))} or \tcode{u8identifier_of(type_of(r))}, + respectively. +\item + Otherwise, \tcode{r} represents a data member description + $(T, N, A, W, NUA)$\iref{class.mem.general}; + a \tcode{string_view} or \tcode{u8string_view}, respectively, + containing the identifier \tcode{\placeholder{N}}. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{display_string_of}% +\indexlibraryglobal{u8display_string_of}% +\begin{itemdecl} +consteval string_view display_string_of(info r); +consteval u8string_view u8display_string_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An +\impldef{the result of \tcode{display_string_of} and \tcode{u8display_string_of}} +\tcode{string_view} or \tcode{u8string_view}, respectively. + +\pnum +\recommended +Where possible, +implementations should return a string +suitable for identifying the represented construct. +\end{itemdescr} + +\indexlibraryglobal{source_location_of}% +\begin{itemdecl} +consteval source_location source_location_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +If \tcode{r} represents +a value, +a type other than a class type or an enumeration type, +the global namespace, or +a data member description, +then \tcode{source_location\{\}}. +Otherwise, an +\impldef{the value returned by \tcode{std::meta::source_location_of}} +\tcode{source_location} value. + +\pnum +\recommended +If \tcode{r} represents an entity with a definition +that is reachable from the evaluation context, +a value corresponding to a definition should be returned. +\end{itemdescr} + +\rSec2[meta.reflection.queries]{Reflection queries} + +\begin{itemdecl} +consteval bool @\exposid{has-type}@(info r); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a +value, +annotation, +object, +variable, +function whose type does not contain an undeduced placeholder type +and that is not a constructor or destructor, +enumerator, +non-static data member, +unnamed bit-field, +direct base class relationship, or +data member description. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{type_of}% +\begin{itemdecl} +consteval bool type_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{\exposid{has-type}(r)} is \tcode{true}. + +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents a + value, + object, + variable, + function, + non-static data member, or + unnamed bit-field, + then the type of what is represented by \tcode{r}. +\item + Otherwise, if \tcode{r} represents an annotation, + then \tcode{type_of(constant_of(r))}. +\item + Otherwise, if \tcode{r} represents + an enumerator $N$ of an enumeration $E$, then: + \begin{itemize} + \item + If $E$ is defined by a declaration $D$ + that precedes a point $P$ in the evaluation context + and $P$ does not occur within an \grammarterm{enum-specifier} of $D$, + then a reflection of $E$. + \item + Otherwise, a reflection of the type of $N$ + prior to the closing brace of the \grammarterm{enum-specifier} + as specified in~\ref{dcl.enum}. + \end{itemize} +\item + Otherwise, if \tcode{r} represents + a direct base class relationship $(D, B)$, + then a reflection of $B$. +\item + Otherwise, for a data member description $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general}, + a reflection of the type $T$. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{object_of}% +\begin{itemdecl} +consteval info object_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{r} is a reflection representing either +\begin{itemize} +\item + an object with static storage duration\iref{basic.stc.general}, or +\item + a variable that either declares or refers to such an object, + and if that variable is a reference $R$, then either + \begin{itemize} + \item + $R$ is usable in constant expressions\iref{expr.const}, or + \item + the lifetime of $R$ began within the core constant expression + currently under evaluation. + \end{itemize} +\end{itemize} + +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents an object, + then \tcode{r}. +\item + Otherwise, if \tcode{r} represents a reference, + then a reflection of the object referred to by that reference. +\item + Otherwise, \tcode{r} represents a variable; + a reflection of the object declared by that variable. +\end{itemize} +\begin{example} +\begin{codeblock} +int x; +int& y = x; + +static_assert(^^x != ^^y); // OK, \tcode{r} and \tcode{y} are different variables so their + // reflections compare different +static_assert(object_of((^^x) == object_of(^^y))); // OK, because \tcode{y} is a reference + // to \tcode{x}, their underlying objects are the same +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{constant_of}% +\begin{itemdecl} +consteval info constant_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $R$ be a constant expression of type \tcode{info} +such that \tcode{$R$ == r} is \tcode{true}. +If \tcode{r} represents an annotation, +then let $C$ be its underlying constant. + +\pnum +\constantwhen +Either \tcode{r} represents an annotation or +\tcode{[: $R$ :]} is a valid +\grammarterm{splice-expression}\iref{expr.prim.splice}. + +\pnum +\effects +Equivalent to: +%FIXME: surely, this is meant to be is_annotation(r) +\begin{codeblock} +if constexpr (is_annotation(R)) { + return @$C$@; +} else { + return reflect_constant([: @$R$@ :]); +} +\end{codeblock} +\begin{example} +\begin{codeblock} +constexpr int x = 0; +constexpr int y = 0; + +static_assert(^^x != ^^y); // OK, \tcode{x} and \tcode{y} are different variables so their + // reflections compare different +static_assert(constant_of(^^x) == constant_of(^^y)); // OK, both \tcode{constant_of(x)} and + // \tcode{constant_of(\reflexpr{y})} + // represent the value \tcode{0} +static_assert(constant_of(^^x) == reflect_constant(0)); // OK, likewise + +struct S { int m; }; +constexpr S s {42}; +static_assert(is_object(constant_of(^^s)) && + is_object(reflect_object(s))); +static_assert(constant_of(^^s) != reflect_object(s)); // OK, template parameter object that is + // template-argument-equivalent to \tcode{s} is + // a different object than \tcode{s} +static_assert(constant_of(^^s) == + constant_of(reflect_object(s))); // OK + +consteval info fn() { + constexpr int x = 42; + return ^^x; +} +constexpr info r = constant_of(fn()); // error: \tcode{x} is outside its lifetime +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{is_public}% +\indexlibraryglobal{is_protected}% +\indexlibraryglobal{is_private}% +\begin{itemdecl} +consteval bool is_public(info r); +consteval bool is_protected(info r); +consteval bool is_private(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents either +\begin{itemize} +\item + a class member or unnamed bit-field + that is public, protected, or private, respectively, or +\item + a direct base class relationship $(D, B)$ for which $B$ is, respectively, + a public, protected, or private base class of $D$. +\end{itemize} +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_virtual}% +\begin{itemdecl} +consteval bool is_virtual(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents either a virtual member function +or a direct base class relationship $(D, B)$ +for which $B$ is a virtual base class of $D$. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_pure_virtual}% +\indexlibraryglobal{is_override}% +\begin{itemdecl} +consteval bool is_pure_virtual(info r); +consteval bool is_override(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a member function that is pure virtual +or overrides another member function, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_final}% +\begin{itemdecl} +consteval bool is_final(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a final class or a final member function. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_deleted}% +\indexlibraryglobal{is_defaulted}% +\begin{itemdecl} +consteval bool is_deleted(info r); +consteval bool is_defaulted(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a function that is +a deleted function\iref{dcl.fct.def.delete} +or defaulted function\iref{dcl.fct.def.default}, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_used_provided}% +\indexlibraryglobal{is_user_declared}% +\begin{itemdecl} +consteval bool is_user_provided(info r); +consteval bool is_user_declared(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a function that is +user-provided or user-declared\iref{dcl.fct.def.default}, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_explicit}% +\begin{itemdecl} +consteval bool is_explicit(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a member function that is declared explicit. +Otherwise, \tcode{false}. +\begin{note} +If \tcode{r} represents a member function template that is declared explicit, +\tcode{is_explicit(r)} is still \tcode{false} +because in general, +such queries for templates cannot be answered. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{is_noexcept}% +\begin{itemdecl} +consteval bool is_noexcept(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a \tcode{noexcept} function type +or a function with a non-throwing exception specification\iref{except.spec}. +Otherwise, \tcode{false}. +\begin{note} +If \tcode{r} represents a function template that is declared \tcode{noexcept}, +\tcode{is_noexcept(r)} is still \tcode{false} +because in general, +such queries for templates cannot be answered. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{is_bit_field}% +\begin{itemdecl} +consteval bool is_bit_field(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a bit-field, +or if \tcode{r} represents a data member description +$(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} +for which $W$ is not $\perp$. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_enumerator}% +\indexlibraryglobal{is_annotation}% +\begin{itemdecl} +consteval bool is_enumerator(info r); +consteval bool is_annotation(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents an enumerator or annotation, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_const}% +\indexlibraryglobal{is_volatile}% +\begin{itemdecl} +consteval bool is_const(info r); +consteval bool is_volatile(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a const or volatile type, respectively, +or a const- or volatile-qualified function type, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_mutable_member}% +\begin{itemdecl} +consteval bool is_mutable_member(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a \tcode{mutable} non-static data member. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_lvalue_reference_qualified}% +\indexlibraryglobal{is_rvalue_reference_qualified}% +\begin{itemdecl} +consteval bool is_lvalue_reference_qualified(info r); +consteval bool is_rvalue_reference_qualified(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $T$ be \tcode{type_of(r)} if \tcode{\exposid{has-type}(r)} is \tcode{true}. +Otherwise, let $T$ be \tcode{dealias(r)}. + +\pnum +\returns +\tcode{true} if $T$ represents an +lvalue- or rvalue-qualified function type, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{has_static_storage_duration}% +\indexlibraryglobal{has_thread_storage_duration}% +\indexlibraryglobal{has_automatic_storage_duration}% +\begin{itemdecl} +consteval bool has_static_storage_duration(info r); +consteval bool has_thread_storage_duration(info r); +consteval bool has_automatic_storage_duration(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents an object or variable that has +static, thread, or automatic storage duration, respectively\iref{basic.stc}. +Otherwise, \tcode{false}. +\begin{note} +It is not possible to have a reflection +representing an object or variable having dynamic storage duration. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{has_internal_linkage}% +\indexlibraryglobal{has_module_linkage}% +\indexlibraryglobal{has_external_linkage}% +\indexlibraryglobal{has_c_language_linkage}% +\indexlibraryglobal{has_linkage}% +\begin{itemdecl} +consteval bool has_internal_linkage(info r); +consteval bool has_module_linkage(info r); +consteval bool has_external_linkage(info r); +consteval bool has_c_language_linkage(info r); +consteval bool has_linkage(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a variable, function type, template, or namespace +whose name has +internal linkage, +module linkage, +C language linkage, or +any linkage, respectively\iref{basic.link}. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_copmlete_type}% +\begin{itemdecl} +consteval bool is_complete_type(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{is_type(r)} is \tcode{true} +and there is some point in the evaluation context +from which the type represented by \tcode{dealias(r)} +is not an incomplete type\iref{basic.types}. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_enumerable_type}% +\begin{itemdecl} +consteval bool is_enumerable_type(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +A type $T$ is \term{enumerable} from a point $P$ if either +\begin{itemize} +\item + $T$ is a class type complete at point $P$ or +\item + $T$ is an enumeration type defined by a declaration $D$ + such that $D$ is reachable from $P$ + but $P$ does not occur within an \grammarterm{enum-specifier} of $D$\iref{dcl.enum}. +\end{itemize} + +\pnum +\returns +\tcode{true} if \tcode{dealias(r)} represents a type that is enumerable +from some point in the evaluation context. +Otherwise, \tcode{false}. +\begin{example} +\begin{codeblock} +class S; +enum class E; +static_assert(!is_enumerable_type(^^S)); +static_assert(!is_enumerable_type(^^E)); + +class S { + void mfn() { + static_assert(is_enumerable_type(^^S)); + } + static_assert(!is_enumerable_type(^^S)); +}; +static_assert(is_enumerable_type(^^S)); + +enum class E { + A = is_enumerable_type(^^E) ? 1 : 2 +}; +static_assert(is_enumerable_type(^^E)); +static_assert(static_cast(E::A) == 2); +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{is_variable}% +\begin{itemdecl} +consteval bool is_variable(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a variable. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_type}% +\indexlibraryglobal{is_namespace}% +\begin{itemdecl} +consteval bool is_type(info r); +consteval bool is_namespace(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents an entity +whose underlying entity is a type or namespace, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_type_alias}% +\indexlibraryglobal{is_namespace_alias}% +\begin{itemdecl} +consteval bool is_type_alias(info r); +consteval bool is_namespace_alias(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a type alias or namespace alias, respectively +Otherwise, \tcode{false}. +\begin{note} +A specialization of an alias template is a type alias. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{is_function}% +\begin{itemdecl} +consteval bool is_function(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a function. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_conversion_function}% +\indexlibraryglobal{is_operator_function}% +\indexlibraryglobal{is_literal_operator}% +\begin{itemdecl} +consteval bool is_conversion_function(info r); +consteval bool is_operator_function(info r); +consteval bool is_literal_operator(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a function that is a +conversion function\iref{class.conv.fct}, +operator function\iref{over.oper}, or +literal operator\iref{over.literal}, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_special_member_function}% +\indexlibraryglobal{is_constructor}% +\indexlibraryglobal{is_default_constructor}% +\indexlibraryglobal{is_copy_constructor}% +\indexlibraryglobal{is_move_constructor}% +\indexlibraryglobal{is_assignment}% +\indexlibraryglobal{is_copy_assignment}% +\indexlibraryglobal{is_move_assignment}% +\indexlibraryglobal{is_destructor}% +\begin{itemdecl} +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); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a function that is a +special member function\iref{special}, +a constructor, +a default constructor, +a copy constructor, +a move constructor, +an assignment operator, +a copy assignment operator, +a move assignment operator, or +a destructor, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_template}% +\begin{itemdecl} +consteval bool is_template(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a +function template, +class template, +variable template, +alias template, or +concept. +Otherwise, \tcode{false}. + +\pnum +\begin{note} +A template specialization is not a template. +For example, +\tcode{is_template(\brk{}\reflexpr{std::vector})} is \tcode{true} +but \tcode{is_template(\brk{}\reflexpr{std::vector})} is \tcode{false}. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{is_function_template}% +\indexlibraryglobal{is_variable_template}% +\indexlibraryglobal{is_class_template}% +\indexlibraryglobal{is_alias_template}% +\indexlibraryglobal{is_conversion_function_template}% +\indexlibraryglobal{is_operator_function_template}% +\indexlibraryglobal{is_literal_operator_template}% +\indexlibraryglobal{is_constructor_template}% +\indexlibraryglobal{is_concept}% +\begin{itemdecl} +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); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a +function template, +variable template, +class template, +alias template, +conversion function template, +literal operator template, +constructor template, or +concept, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_value}% +\indexlibraryglobal{is_object}% +\begin{itemdecl} +consteval bool is_value(info r); +consteval bool is_object(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a value or object, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_structured_binding}% +\begin{itemdecl} +consteval bool is_structured_binding(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a structured binding. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_class_member}% +\indexlibraryglobal{is_namespace_member}% +\indexlibraryglobal{is_nonstatic_data_member}% +\indexlibraryglobal{is_static_member}% +\indexlibraryglobal{is_base}% +\begin{itemdecl} +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); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a +class member, +namespace member, +non-static data member, +static member, or +direct base class relationship, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{has_default_member_initializer}% +\begin{itemdecl} +consteval bool has_default_member_initializer(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a non-static data member +that has a default member initializer. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{has_parent}% +\begin{itemdecl} +consteval bool has_parent(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents the global namespace, + then \tcode{false}. +\item + Otherwise, if \tcode{r} represents an entity that has C language linkage\iref{dcl.link}, + then \tcode{false}. +\item + Otherwise, if \tcode{r} represents an enitity that has a + language linkage other than \Cpp{} language linkage, + then an + \impldef{the result of \tcode{std::meta::has_parent} for entities + with neither C nor \Cpp{} language linkage} + value. +\item + Otherwise, if \tcode{r} represents a type that is neither a class nor enumeration type, + then \tcode{false}. +\item + Otherwise, if \tcode{r} represents an enity or direct base class relationship, + then \tcode{true}. +\item + Otherwise, \tcode{false}. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{parent_of}% +\begin{itemdecl} +consteval info parent_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{has_parent(r)} is \tcode{true}. + +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents a non-static data member + that is a direct member of an anonymous union, + or an unnamed bit-field declared + within the \grammarterm{member-specification} of such a union, + then a reflection representing the innermost enclosing anonymous union. +\item + Otherwise, if \tcode{r} represents an enumerator, + then a reflection representing the corresponding enumeration type. +\item + Otherwise, if \tcode{r} represents a direct base class relationship $(D, B)$, + then a reflection representing $D$. +\item + Otherwise, let $E$ be a class, function, or namespace + whose class scope, function parameter scope, or namespace scope, respectively, + is the innermost such scope that either is, or encloses, + the target scope of a declaration of what is represented by \tcode{r}. + \begin{itemize} + \item + If $E$ is the function call oeprator of a closure type + for a \grammarterm{consteval-block-declaration}\iref{dcl.pre}, + then \tcode{parent_of(\brk{}parent_of(\reflexpr{$E$}))}. + \begin{note} + In this case, + the first \tcode{parent_of} will be the closure type, + so the second \tcode{parent_of} is necessary + to give the parent of that closure type. + \end{note} + \item + Otherwise, \tcode{\reflexpr{$E$}}. + \end{itemize} +\end{itemize} +\begin{example} +\begin{codeblock} +struct I { }; + +struct F : I { + union { + int o; + }; + + enum N { + A + }; +}; + +constexpr auto ctx = std::meta::access_context::current(); + +static_assert(parent_of(^^F) == ^^::); +static_assert(parent_of(bases_of(^^F, ctx)[0]) == ^^F); +static_assert(is_union_type(parent_of(^^F::o))); +static_assert(parent_of(^^F::N) == ^^F); +static_assert(parent_of(^^F::A) == ^^F::N); +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{delias}% +\begin{itemdecl} +consteval info dealias(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{r} represents an entity. + +\pnum +\returns +A reflection representing the underlying entity of what \tcode{r} represents. +\begin{example} +\begin{codeblock} +using X = int; +using Y = X; +static_assert(dealias(^^int) == ^^int); +static_assert(dealias(^^X) == ^^int); +static_assert(dealias(^^Y) == ^^int); +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{has_template_arguments}% +\begin{itemdecl} +consteval bool has_template_arguments(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a specialization of a +function template, +variable template, +class template, or +an alias template. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{template_of}% +\begin{itemdecl} +consteval info template_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{has_template_arguments(r)} is \tcode{true}. + +\pnum +\returns +A reflection of the template of the specialization represented by \tcode{r}. +\end{itemdescr} + +\indexlibraryglobal{template_arguments_of}% +\begin{itemdecl} +consteval vector template_arguments_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{has_template_arguments(r)} is \tcode{true}. + +\pnum +\returns +A \tcode{vector} containing reflections +of the template arguments +of the template specialization represented by \tcode{r}, +in the order they appear in the corresponding template argument list. +For a given template argument $A$, +its corresponding reflection $R$ is determined as follows: +\begin{itemize} +\item + If $A$ denotes a type or type alias, + then $R$ is a reflection representing the underlying entity of $A$. + \begin{note} + $R$ always represents a type, never a type alias. + \end{note} +\item + Otherwise, if $A$ denotes a + class template, + variable template, + concept, or + alias template, + then $R$ is a reflection representing $A$. +\item + Otherwise, $A$ is a constant template argument\iref{temp.arg.nontype}. + Let $P$ be the corresponding template parameter. + \begin{itemize} + \item + If $P$ has reference type, + then $R$ is a reflection + representing the object or function referred to by $A$. + \item + Otherwise, if $P$ has class type, + then $R$ represents the corresponding template parameter object. + \item + Otherwise, $R$ is a reflection representing the value of $A$. + \end{itemize} +\end{itemize} +\begin{example} +\begin{codeblock} +template struct Pair { }; +template struct Pair { }; +template using PairPtr = Pair; + +static_assert(template_of(^^Pair) == ^^Pair); +static_assert(template_of(^^Pair) == ^^Pair); +static_assert(template_arguments_of(^^Pair).size() == 2); +static_assert(template_arguments_of(^^Pair)[0] == ^^int); + +static_assert(template_of(^^PairPtr) == ^^PairPtr); +static_assert(template_arguments_of(^^PairPtr).size() == 1); + +struct S { }; +int i; +template class> + struct X { }; +constexpr auto T = ^^X<1, i, S{}, PairPtr>; +static_assert(is_value(template_arguments_of(T)[0])); +static_assert(is_object(template_arguments_of(T)[1])); +static_assert(is_object(template_arguments_of(T)[2])); +static_assert(template_arguments_of(T)[3] == ^^PairPtr); +\end{codeblock} +\end{example} +\end{itemdescr} + +\rSec2[meta.reflection.access.context]{Access control context} + +\pnum +The \tcode{access_context} class is a non-aggregate type +that represents a namespacee, class, or function +from which queries pertaining to access rules may be performed, +as well as the designating class\iref{class.access.base}, if any. + +\indexlibraryglobal{access_context}% +\pnum +An \tcode{access_context} has an associated scope and designating class. + +\begin{itemdecl} +struct access_context { + access_context() = delete; + + consteval info scope() const; + consteval info designating_class() const; + + static consteval access_context current() noexcept; + static consteval access_context unprivileged() noexcept; + static consteval access_context unchecked() noexcept; + consteval access_context via(info cls) const; +}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\tcode{access_context} is a structural type. +Two values \tcode{ac1} and \tcode{ac2} of type \tcode{access_context} +are template-argument-equivalent\iref{temp.type} +if \tcode{a1.scope()} and \tcode{a2.scope()} +are template-argument-equivalent +and \tcode{ac1.desig\-nating_class()} and \tcode{ac2.desig\-nating_class()} +are template-argument-equivalent. +\end{itemdescr} + +\begin{itemdecl} +consteval info @\libmember{scope}{access_context}@() const; +consteval info @\libmember{designating_class}{access_context}@() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The \tcode{access_context}'s associated scope +and designating class, respectively. +\end{itemdescr} + +\begin{itemdecl} +static consteval access_context @\libmember{current}{access_context}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +Given a program point $P$, +let \tcode{\exposid{eval-point}(P)} be the following program point: +\begin{itemize} +\item + If a potentially-evaluated subexpression\iref{intro.execution} + of a default member initializer $I$ + for a member of class $C$\iref{class.mem.general} + appears at $P$, + then a point determined as follows: + \begin{itemize} + \item + If an aggregate initialization is using $I$, + \tcode{\exposid{eval-point}($Q$)}, + where $Q$ is the point at which that aggregate initialization appears. + \item + Otherwise, if an initialization + by an inherited constructor\iref{class.inhctor.init} is using $I$, + a point whose immediate scope is the class scope corresponding to $C$. + \item + Otherwise, a point whose immediate scope + is the function parameter scope + corresponding to the constructor definition that is using $I$. + \end{itemize} + \item + Otherwise, if a potentially-evaluated subexpression + of a default argument\iref{dcl.fct.default} appears at $P$, + \tcode{\exposid{eval-point}($Q$)}, + where $Q$ is the point at which the invocation of the function\iref{expr.call} + using that default argument appears. + \item + Otherwise, if the immediate scope of $P$ + is a function parameter scope introduced by a declaration $D$, + and $P$ appears either before the locus of $D$ + or within the trailing \grammarterm{requires-clause} of $D$, + a point whose immediate scope is the innermost scope enclosing the locus of $D$ + that is not a template parameter scope. + \item + Otherwise, if the immediate scope of $P$ + is a function parameter scope + introduced by a \grammarterm{lambda-expression} $L$ + whose \grammarterm{lambda-introducer} appears at point $Q$, + and $P$ appears either within the \grammarterm{trailing-return-type} + or the trailing \grammarterm{requires-clause} of $L$, + \tcode{\exposid{eval-point}($Q$)}. + \item + Otherwise, if the innermost non-block scope enclosing $P$ + is the function parameter scope + introduced by a \grammarterm{consteval-block-declaration}\iref{dcl.pre}, + a point whose immediate scope is that inhabited + by the outermost \grammarterm{consteval-block-declaration} $D$ + containing $P$ such that each scope (if any) that intervenes between $P$ + and the function parameter scope introduced by $D$ is either + \begin{itemize} + \item + a block scope or + \item + a function parameter scope or lambda or lambda scope + introduced by a \grammarterm{consteval-block-declaration}. + \end{itemize} + \item + Otherwise, $P$. +\end{itemize} + +\pnum +Given a scope $S$, +let \tcode{\exposid{ctx-scope}($S$)} be the following scope: +\begin{itemize} +\item + If $S$ is a class scope or namespace scope, + $S$. +\item + Otherwise, if $S$ is a function parameter scope + introduced by the declaration of a function, + $S$. +\item + Otherwise, if $S$ is a lambda scope + introduced by a \grammarterm{lambda-expression} $L$, + the function parameter scope + corresponding to the call operator of the closure type of $L$. +\item + Otherwise, \tcode{\exposid{ctx-scope}($S'$)}, + where $S'$ is the parent scope of $S$. +\end{itemize} + +\pnum +\returns +An \tcode{access_context} whose designating class is the null reflection +and whose scope represents the function, class, or namespace +whose corresponding function parameter scope, class scope, or namespace scope, respectively, +is \tcode{\exposid{ctx-scope}($S$)}, +where $S$ is the immediate scope of \tcode{\exposid{eval-point}($P$)} +and $P$ is the point at which the invocation of \tcode{current} lexically appears. +\begin{example} +\begin{codeblock} +struct A { + int a = 0; + consteval A(int p) : a(p) {} +}; +struct B : A { + using A::A; + consteval B(int p, int q) : A(p * q) {} + info s = access_context::current().scope(); +}; +struct C : B { using B::B; }; + +struct Agg { + consteval bool eq(info rhs = access_context::current().scope()) { + return s == rhs; + } + info s = access_context::current().scope(); +}; + +namespace NS { + static_assert(Agg{}.s == access_context::current().scope()); // OK + static_assert(Agg{}.eq()); // OK + static_assert(B(1).s == ^^B); // OK + static_assert(is_constructor(B{1, 2}.s) && parent_of(B{1, 2}.s) == ^^B); // OK + static_assert(is_constructor(C{1, 2}.s) && parent_of(C{1, 2}.s) == ^^B); // OK + + auto fn() -> [:is_namespace(access_context::current().scope()) ? ^^int : ^^bool:]; + static_assert(type_of(^^fn) == ^^auto()->int); // OK + + template + struct TCls { + consteval bool fn() + requires (is_type(access_context::current().scope())) { + return true; // OK, scope is \tcode{TCls}. + } + }; + static_assert(TCls<0>{}.fn()); // OK +} +\end{codeblock} +\end{example} + +\pnum +\remarks +\tcode{current} is not an addressable function\iref{namespace.std}. +An invocation of \tcode{current} that appears at a program point $P$ +is value-dependent\iref{temp.dep.constexpr} +if \tcode{\exposid{eval-point}\brk{}(\brk{}$P$)} is enclosed by a scope +corresponding to a templated entity. +\end{itemdescr} + +\begin{itemdecl} +static consteval access_context @\libmember{unprivileged}{access_context}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An \tcode{access_context} whose designating class is the null reflection +and whose scope is the global namespace. +\end{itemdescr} + +\begin{itemdecl} +static consteval access_context @\libmember{unchecked}{access_context}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An \tcode{access_context} whose designating class and scope +are both the null reflection. +\end{itemdescr} + +\begin{itemdecl} +static consteval access_context @\libmember{via}{access_context}@(info cls) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{cls} is either the null reflection +or a reflection of a complete class type. + +\pnum +\returns +An \tcode{access_context} whose scope is \tcode{this->scope()} +and whose designating class is \tcode{cls}. +\end{itemdescr} + +\rSec2[meta.reflection.access.queries]{Member accessibility queries} + +\indexlibraryglobal{is_accessible}% +\begin{itemdecl} +consteval bool is_accessible(info r, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\exposid{PARENT-CLS}(r)} be: +\begin{itemize} +\item If \tcode{parent_of(r)} represents a class $C$, then $C$. +\item Otherwise, \tcode{\exposid{PARENT-CLS}(parent_of(r))}. +\end{itemize} + +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{r} does not represent a class member + for which \tcode{\exposid{PARENT-CLS}(r)} is an incomplete class and +\item + \tcode{r} does not represent a direct base class relationship $(D, B)$ + for which $D$ is incomplete. +\end{itemize} + +\pnum +Let \tcode{\exposid{DESIGNATING-CLS}(r, ctx)} be: +\begin{itemize} +\item If \tcode{ctx.designating_class()} represents a class $C$, then $C$. +\item Otherwise, \tcode{\exposid{PARENT-CLS}(r)}. +\end{itemize} + +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents an unnamed bit-field $F$, + then \tcode{is_accessible($\tcode{r}_H$, ctx)}, + where $\tcode{r}_H$ represents a hypothetical non-static data member + of the class represented by \tcode{\exposid{PARENT-CLS}(r)} + with the same access as $F$. + \begin{note} + Unnamed bit-fields are treated as class members + for the purpose of \tcode{is_accessible}. + \end{note} +\item + Otherwise, if \tcode{r} does not represent a class member + or a direct base class relationship, + then \tcode{true}. +\item + Otherwise, if \tcode{r} represents + \begin{itemize} + \item + a class member that is not a (possibly indirect or variant) + member of \tcode{\exposid{DESIG\-NATING-CLS}(\brk{}r, ctx)} or + \item + a direct base class relationship such that \tcode{parent_of(r)} + does not represent \tcode{\exposid{DESIG\-NATING-CLS}(\brk{}r, ctx)} + or a (direct or indirect) base class thereof, + \end{itemize} + then \tcode{false}. +\item + Otherwise, if \tcode{ctx.scope()} is the null reflection, + then \tcode{true}. +\item + Otherwise, letting $P$ be a program point whose immediate scope is the + function parameter scope, class scope, or namespace scope + corresponding to the + function, class, or namespace + represented by \tcode{ctx.scope()}: + \begin{itemize} + \item + If \tcode{r} represents a direct base class relationship $(D, B)$, + then \tcode{true} if base class $B$ of \tcode{\exposid{DESIG\-NATING-CLS}(\brk{}r, ctx)} + is accessible at $P$\iref{class.access.base}; + otherwise \tcode{false}. + \item + Otherwise, \tcode{r} represents a class member $M$; + \tcode{true} if $M$ would be accessible at $P$ + with the designating class\iref{class.access.base} as \tcode{\exposid{DESIG\-NATING-CLS}(r, ctx)} + if the effect of any \grammarterm{using-declaration}s\iref{namespace.udecl} were ignored. + Otherwise, \tcode{false}. + \end{itemize} +\end{itemize} +\begin{note} +The definitions of when a class member or base class is accessible from a point $P$ +do not consider whether a declaration of that entity is reachable from $P$. +\end{note} +\begin{example} +\begin{codeblock} +consteval access_context fn() { + return access_context::current(); +} + +class Cls { + int mem; + friend consteval access_context fn(); +public: + static constexpr auto r = ^^mem; +}; + +static_assert(is_accessible(Cls::r, fn())); // OK +static_assert(!is_accessible(Cls::r, access_context::current())); // OK +static_assert(is_accessible(Cls::r, access_context::unchecked())); // OK +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{has_inaccessible_nonstatic_data_members}% +\begin{itemdecl} +consteval bool has_inaccessible_nonstatic_data_members(info r, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{nonstatic_data_members_of(\brk{}r, access_context::\brk{}unchecked())} + is a constant subexpression and +\item + \tcode{r} does not represent a closure type. +\end{itemize} + +\pnum +\returns +\tcode{true} if \tcode{is_accessible($R$, ctx)} is \tcode{false} +for any $R$ in \tcode{nonstatic_data_members_of(\brk{}r, access_context\brk{}::unchecked())}. +Otherwise, \tcode{false}. +\end{itemdescr} + +\begin{itemdecl} +consteval bool has_inaccessible_bases(info r, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{bases_of(r, access:context::unchecked())} +is a constant subexpression. + +\pnum +\returns +\tcode{true} if \tcode{is_accessible($R$, ctx)} is \tcode{false} +for any $R$ in \tcode{bases_of(\brk{}r, access_context\brk{}::unchecked())}. +Otherwise, \tcode{false}. +\end{itemdescr} + +\rSec2[meta.reflection.member.queries]{Reflection member queries} + +\indexlibraryglobal{members_of}% +\begin{itemdecl} +consteval vector members_of(info r, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(r)} is a reflection representing either +a class type that is complete from some point in the evaluation context +or a namespace. + +\pnum +A declaration $D$ \term{members-of-precedes} a point $P$ +if $D$ precedes either $P$ +or the point immediately following the \grammarterm{class-specifier} +of the outermost class for which $P$ is in a complete-class context. + +\pnum +A declaration $D$ of a member $M$ of a class or namespace $Q$ is +\term{$Q$-members-of-eligible} if +\begin{itemize} +\item + the host scope of $D$\iref{basic.scope.scope} + is the class scope or namespace scope associated with $Q$, +\item + $D$ is not a friend declaration, +\item + $M$ is not a closure type\iref{expr.prim.lambda.closure}, +\item + $M$ is not a specialization of a template\iref{temp.pre}, +\item + if $Q$ is a class that is not a closure type, + then $M$ is a direct member of $Q$\iref{class.mem.general} + that is not a variant member of a + nested anonymous union of $Q$\iref{class.union.anon}, and +\item + if $Q$ is a closure type, + then $M$ is a function call operator or function call operator template. +\end{itemize} +It is \impldef{whether declarations of some members of a closure type $Q$ +are $Q$-members-of-eliible} +whether declarations of other members of a closure type $Q$ +are $Q$-members-of-eligible. + +\pnum +A member $M$ of a class or namespace $Q$ is +\term{$Q$-members-of-representable} from a point $P$ +if a $Q$-members-of-eligible declaration of $M$ members-of-precedes $P$, +and $M$ is +\begin{itemize} +\item + a class or enumeration type +\item + a type alias +\item + a class template, function template, + variable template, alias template, or concept, +\item + a variable or reference $V$ + for which the type of $V$ does not contain an undeduced placeholder type, +\item + a function $F$ for which + \begin{itemize} + \item + the type of $F$ does not contain an undeduced placeholder type, + \item + the constraints (if any) of $F$ are satisfied, and + \item + if $F$ is a prospective destructor, + $F$ is the selected destructor\iref{class.dtor}, + \end{itemize} +\item + a non-static data member, +\item + a namesapce, or +\item + a namespace alias. +\end{itemize} +\begin{note} +Examples of direct members that are not $Q$-members-of-representable +for any entity $Q$ include: +unscoped enumerators\iref{enum}, +partial specializations of templates\iref{temp.spec.partial}, and +closure types\iref{expr.prim.lambda.closure}. +\end{note} + +\pnum +\returns +A \tcode{vector} containing reflections of all members $M$ +of the entity $Q$ represented by \tcode{dealias(r)} for which +\begin{itemize} +\item + $M$ is $Q$-members-of-representable + from some point in the evaluation context and +\item + \tcode{is_accessible(\reflexpr{$M$}, ctx)} is \tcode{true}. +\end{itemize} +If \tcode{dealias(r)} represents a class $C$, +then the \tcode{vector} also contains reflections +representing all unnamed bit-fields $B$ +whose declarations inhabit the class scope corresponding to $C$ +for which \tcode{is_accessible(\reflexpr{$B$}, ctx)} is \tcode{true}. +Reflections of class members and unnamed bit-fields that are declared +appear in the order in which they are declared. +\begin{note} +Base classes are not members. +Implicitly-declared special members +appear after any user-declared members\iref{special}. +\end{note} +\begin{example} +\begin{codeblock} +// TU1 +export module M; +namespace NS { + export int m; + static int l; +} +static_assert(members_of(^^NS, access_context::current()).size() == 2); + +// TU2 +import M; + +static_assert( // \tcode{NS::l} does not precede + members_of(^^NS, access_context::current()).size() == 1); // the constant-expression\iref{basic.lookup} + +class B {}; + +struct S : B { +private: + class I; +public: + int m; +}; + +static_assert( // 6 special members, + members_of(^^S, access_context::current()).size() == 7); // 1 public member, + // does not include base + +static_assert( // all of the above, + members_of(^^S, access_context::unchecked()).size() == 8); // as well as a reflection + // representing \tcode{S::I} +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{bases_of}% +\begin{itemdecl} +consteval vector bases_of(info type, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(type)} represents a class type +that is complete from some point in the evaluation context. + +\pnum +\returns +Let $C$ be the class represented by \tcode{dealias(type)}. +A \tcode{vector} containing the reflections +of all the direct base class relationships of $B$, if any, +of $C$ such that \tcode{is_accessible(\brk{}\reflexpr{B}, txt)} is \tcode{true}. +The direct base class relationships appear in the order in which +the corresponding base classes appear in the \grammarterm{base-specifier-list} of $C$. +\end{itemdescr} + +\indexlibraryglobal{static_data_members_of}% +\begin{itemdecl} +consteval vector static_data_members_of(info type, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(type)} represents a class type +that is complete from some point in the evaluation context. + +\pnum +\returns +A \tcode{vector} containing each element \tcode{e} of \tcode{members_of(type, ctx)} +such that \tcode{is_variable(e)} is \tcode{true}, +preserving their order. +\end{itemdescr} + + +\indexlibraryglobal{nonstatic_data_members_of}% +\begin{itemdecl} +consteval vector nonstatic_data_members_of(info type, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(type)} represents a class type +that is complete from some point in the evaluation context. + +\pnum +\returns +A \tcode{vector} containing each element \tcode{e} of \tcode{members_of(type, ctx)} +such that \tcode{is_nonstatic_data_members_of(e)} is \tcode{true}, +preserving their order. +\end{itemdescr} + +\indexlibraryglobal{enumerators_of}% +\begin{itemdecl} +consteval vector enumerators_of(info type_enum); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(type_enum)} represents an enumeration type, +and \tcode{is_enumerable_type(\brk{}type_enum)} is \tcode{true}. + +\pnum +\returns +A \tcode{vector} containing the reflections of each enumerator +of the enumeration represented by \tcode{dealias(type_enum)}, +in the order in which they are declared. +\end{itemdescr} + +\rSec2[meta.reflection.layout]{Reflection layout queries} + +\indexlibraryglobal{member_offset}% +\indexlibrarymember{member_offset}{total_bits}% +\begin{itemdecl} +struct member_offset { + ptrdiff_t bytes; + ptrdiff_t bits; + constexpr ptrdiff_t total_bits() const; + auto operator<=>(const member_offset&) const = default; +}; + +constexpr ptrdiff_t member_offset::total_bits() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{bytes * CHAR_BIT + bits}. +\end{itemdescr} + +\indexlibraryglobal{offset_of}% +\begin{itemdecl} +consteval member_offset offset_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{r} represents a non-static data member, +unnamed bit-field, or +direct base class relationship $(D, B)$ +for which either $B$ is not a virtual base class +or $D$ is not an abstract class. + +\pnum +Let $V$ be the offset in bits from the beginning of a complete object +of the type represented by \tcode{parent_of(r)} +to the subobject associated with the entity represented by \tcode{r}. + +\pnum +\returns +\tcode{\{$V$ / CHAR_BIT, V \% CHAR_BIT\}}. +\end{itemdescr} + +\indexlibraryglobal{size_of}% +\begin{itemdecl} +consteval size_t size_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(r)} is a reflection of a +type, +object, +value, +variable of non-reference type, +non-static data member that is not a bit-field, +direct base class relationship, or +data member description $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} +where $W$ is not $\perp$. +If \tcode{dealias(r)} represents a type, +then \tcode{is_complete_type(r)} is \tcode{true}. + +\pnum +\returns +If \tcode{r} represents +\begin{itemize} +\item a non-static data member of type $T$, +\item a data member description $(T, N, A, W, \mathit{NUA})$, or +\item \tcode{dealias(r)} represents a type $T$, +\end{itemize} +then \tcode{sizeof($T$)} if $T$ is not a reference type +and \tcode{size_of(\brk{}add_pointer(\brk{}\reflexpr{$T$}))} otherwise. +Otherwise, \tcode{size_of(type_of(r))}. +\begin{note} +It is possible that while \tcode{sizeof(char)\brk{} == size_of(\reflexpr{char})} +is \tcode{true}, +that \tcode{sizeof(char\&)\brk{} == size_of(\brk{}\reflexpr{char}\&)} +is \tcode{false}. +If \tcode{b} represents a direct base class relationship of an empty base class, +then \tcode{size_of(b) > 0} is \tcode{true}. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{alignment_of}% +\begin{itemdecl} +consteval size_t alignment_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(r)} is a reflection of a +type, +object, +value, +variable of non-reference type, +non-static data member that is not a bit-field, +direct base class relationship, or +data member description. +If \tcode{dealias(r)} represents a type, +then \tcode{is_complete_type(r)} is \tcode{true}. + +\pnum +\returns +\begin{itemize} +\item + If \tcode{dealias(r)} represents a type $T$, + then the alignment requirement for the layout-associated type\iref{class.mem.general} + for a non-static data member of type $T$. +\item + Otherwise, if \tcode{dealias(r)} represents a variable or object, + then the alignment requirement of the variable or object. +\item + Otherwise, if \tcode{r} represents a direct base class relationship, + then \tcode{alignment_of(type_of(r))}. +\item + Otherwise, if \tcode{r} represents a non-static data member, + then the alignment requirement of the subobject + associated with the represented entity + within any object of type \tcode{parent_of(r)}. +\item + Otherwise, \tcode{r} represents a data member description + $(\mathit{TR}, N, A, W, \mathit{NUA})$\iref{class.mem.general}. + If $A$ is not $\perp$, + then the value of $A$. + Otherwise, \tcode{alignment_of(\reflexpr{$T$})}. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{bit_size_of}% +\begin{itemdecl} +consteval size_t bit_size_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(r)} is a reflection of a +type, +object, +value, +variable of non-reference type, +non-static data member, +unnamed bit-field, +direct base class relationship, or +data member description. +If \tcode{dealias(r)} represents a type $T$, +there is a point within the evaluation context from which $T$ is not incomplete. + +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents + an unnamed bit-field + or a non-static data member that is a bit-field + with width $W$, + then $W$. +\item + Otherwise, if \tcode{r} represents a data member description + $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} + and $W$ is not $\perp$, + then $W$. +\item + Otherwise, \tcode{CHAR_BIT * size_of(r)}. +\end{itemize} +\end{itemdescr} + +\rSec2[meta.reflection.extract]{Value extraction} + +\pnum +The \tcode{extract} function template may be used +to extract a value out of a reflection when its type is known. + +\pnum +The following are defined for exposition only +to aid in the specification of \tcode{extract}. + +\begin{itemdecl} +template + consteval T @\exposid{extract-ref}@(info r); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +\tcode{T} is a reference type. +\end{note} + +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{r} represents a variable or object of type \tcode{U}, +\item + \tcode{is_convertible_v(*)[],\brk{} remove_reference_t<\brk{}T>(\brk{}*)[]>} + is \tcode{true},\newline and + \begin{note} + The intent is to allow only qualification conversion from \tcode{U} to \tcode{T}. + \end{note} +\item + If \tcode{r} represents a variable, + then either that variable is usable in constant expressions + or its lifetime began within the core constant expression currently under evaluation. +\end{itemize} + +\pnum +\returns +If \tcode{r} represents an object $O$, +then a reference ot $O$. +Otherwise, a reference to the object declared, or referred to, +by the variable represented by \tcode{r}. +\end{itemdescr} + +\begin{itemdecl} +template + consteval T @\exposid{extract-member-or-function}@(info r); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{r} represents a non-static data member with type $X$, + that is not a bit-field, + that is a direct member of class \tcode{C}, + \tcode{T} and \tcode{C} are similar types\iref{conv.qual}, and + \tcode{T} is \tcode{is_convertible_v<\brk{}X C::*, T>} is \tcode{true}; +\item + \tcode{r} represents an implicit object member function + with type \tcode{F} or \tcode{F noexcept} + that is a direct member of a class \tcode{C}, + and \tcode{T} is \tcode{F C::*}; or +\item + \tcode{r} represents a non-member function, + static member function, or + explicit object member function + of function type \tcode{F} or \tcode{F noexcept}, + and \tcode{T} is \tcode{F*}. +\end{itemize} + +\pnum +\returns +\begin{itemize} +\item + If \tcode{T} is a pointer type, + then a pointer value pointing to the function represented by \tcode{r}. +\item + Otherwise, a pointer-to-member value + designating the non-static data member or function represented by \tcode{r}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template + consteval T @\exposid{extract-value}@(info r); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $U$ be the type of the value or object that \tcode{r} represents. + +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{U} is a pointer type, + \tcode{T} and \tcode{U} are similar types\iref{conv.qual}, and + \tcode{is_convertible_v<\brk{}U, T>} is \tcode{true}, +\item + \tcode{U} is not a pointer type + and the cv-unqualified types of \tcode{T} and \tcode{U} are the same, +\item + \tcode{U} is an array type, + \tcode{T} is a pointer type, and + the value \tcode{r} represents is convertible to \tcode{T}, or +\item + \tcode{U} is a closure type, + \tcode{T} is a function pointer type, and + the value that \tcode{r} represents is convertible to \tcode{T}. +\end{itemize} + +\pnum +\returns +\tcode{static_cast([:$R$:])}, +where $R$ is a constant expression of type \tcode{info} +such that \tcode{$R$ == r} is \tcode{true}. +\end{itemdescr} + +\indexlibraryglobal{extract}% +\begin{itemdecl} +template + consteval T extract(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{U} be \tcode{remove_cv_t}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +%FIXME: this is inconsistent with reflect_constant, +%which uses if constexpr, +%and presumably, we could do the same here, with the same semantics. +if (is_reference_type(^^T)) { + return @\exposid{extract-ref}@(r); +} else if constexpr (is_nonstatic_data_member(r) || is_function(r)) { + return @\exposid{extract-member-or-function}@(r); +} else { + return @\exposid{extract-value}@(constant_of(r)); +} +\end{codeblock} +\end{itemdescr} + +\rSec2[meta.reflection.substitute]{Reflection substitution} + +\begin{itemdecl} +template +concept @\deflibconcept{reflection_range}@ = + ranges::@\libconcept{input_range}@ && + @\libconcept{same_as}@, info> && + @\libconcept{same_as}@>, info>; + +template<@\libconcept{reflection_range}@ R = initializer_list> +consteval bool @\libglobal{can_substitute}@(info templ, R&& arguments); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{templ} represents a template, +and every reflection in \tcode{arguments} represents a construct +usable as a template argument\iref{temp.arg}. + +\pnum +Let \tcode{Z} be the template represented by \tcode{templ} +and let \tcode{Args...} be a sequence of prvalue constant expressions +that compute the reflections held by the elements of \tcode{arguments}. + +\pnum +\returns +\tcode{true} if \tcode{Z<[:Args:]...>} is a valid \grammarterm{template-id}\iref{temp.names} +that does not name a function +whose type contains an undeduced placeholder type. +Otherwise, \tcode{false}. + +\pnum +\begin{note} +If forming \tcode{Z<[:Args:]...>} leads to a failure +outside of the immediate context, +the program is ill-formed. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{substitute}% +\begin{itemdecl} +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info substitute(info templ, R&& arguments); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{can_substitute(templ, arguments)} is \tcode{true}. + +\pnum +Let \tcode{Z} be the template represented by \tcode{templ} +and let \tcode{Args...} be a sequence of prvalue constant expressions +that compute the reflections held by the elements of \tcode{arguments}. + +\pnum +\returns +\tcode{\reflexpr{Z<[:Args:]...>}}. + +\pnum +\begin{note} +If forming \tcode{Z<[:Args:]...>} leads to a failure outside of the immedaite context, +the program is ill-formed. +\end{note} + +\pnum +\begin{example} +\begin{codeblock} +template + auto fn1(); + +static_assert(!can_substitute(^^fn1, {^^int})); // OK +constexpr info r1 = substitute(^^fn1, {^^int}); // error: \tcode{fn} contains an undeduced + // placeholder type + +template + auto fn2() { + static_assert(^^T != ^^int); // static assertion failed during instantiation of \tcode{fn} + return 0; + } + +constexpr bool r2 = can_substitute(^^fn2, {^^int}); // error: instantiation of body of \tcode{fn} + // is needed to deduce return type +\end{codeblock} +\end{example} + +\pnum +\begin{example} +\begin{codeblock} +consteval info to_integral_constant(unsigned i) { + return substitute(^^integral_constant, {^^unsigned, reflect_constant(i)}); +} +constexpr info r = to_integral_constant(2); // OK, \tcode{r} represents the type + // \tcode{integral_constant} +\end{codeblock} +\end{example} +\end{itemdescr} + +\rSec2[meta.reflection.result]{Expression result reflection} + +\indexlibraryglobal{reflect_constant}% +\begin{itemdecl} +template + consteval info reflect_constant(T expr); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_copy_constructible_v} is \tcode{true} +and \tcode{T} is a cv-unqualified structural type\iref{temp.param} +that is not a reference type. + +\pnum +Let $V$ be: +\begin{itemize} +\item + if \tcode{T} is a class type, + then an object that is template-argument-equivalent to the value of \tcode{expr}; +\item + otherwise, the value of \tcode{expr}. +\end{itemize} + +\pnum +\constantwhen +given the invented variable +\begin{codeblock} +template struct TCls; +\end{codeblock} +the \grammarterm{template-id} \tcode{TCls<$V$>} would be valid. + +\pnum +\returns +\tcode{template_arguments_of(\reflexpr{TCls<$V$>})[0]}. +\begin{note} +This is a reflection of an object for class types, +and a reflection of a value otherwise. +\end{note} +\begin{example} +\begin{codeblock} +template + struct A { }; + +struct N { int x; }; +struct K { char const* p; }; + +constexpr info r1 = reflect_constant(42); +static_assert(is_value(r1)); +static_assert(r1 == template_arguments_of(^^A<42>)[0]); + +constexpr info r2 = reflect_constant(N{42}); +static_assert(is_object(r2)); +static_assert(r2 == template_arguments_of(^^A)[0]); + +constexpr info r3 = reflect_constant(K{nullptr}); // OK +constexpr info r4 = reflect_constant(K{"ebab"}); // error: constituent pointer points to string literal +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{reflect_object}% +\begin{itemdecl} +template + consteval info reflect_object(T& expr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is an object type. + +\pnum +\constantwhen +\tcode{expr} is suitable for use as a constant template argument +for a constant template parameter of type \tcode{T\&}\iref{temp.arg.nontype}. + +\pnum +\returns +A reflection of the object designated by \tcode{expr}. +\end{itemdescr} + +\indexlibraryglobal{reflect_function}% +\begin{itemdecl} +template + consteval info reflect_function(T& expr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is a function type. + +\pnum +\constantwhen +\tcode{expr} is suitable for use as a constant template argument +for a constant template parameter of type \tcode{T\&}\iref{temp.arg.nontype}. + +\pnum +\returns +A reflection of the function designated by \tcode{fn}. +\end{itemdescr} + +\rSec2[meta.reflection.define.aggregate]{Reflection class definition generation} + +\begin{itemdecl} +struct data_member_options { + struct @\exposid{name-type}@ { // \expos + template + requires @\libconcept{constructible_from}@ + consteval @\exposid{name-type}@(T&&); + + template + requires @\libconcept{constructible_from}@ + consteval @\exposid{name-type}@(T&&); + + private: + variant @\exposid{contents}@; // \expos + }; + + optional<@\exposid{name-type}@> name; + optional alignment; + optional bit_width; + bool no_unique_address = false; +}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The classes \tcode{data_member_options} +and \tcode{data_member_options::\brk{}\exposid{name-type}} +are consteval-only types\iref{basic.types.general}, +and are not structural types\iref{temp.param}. +\end{itemdescr} + +\begin{itemdecl} +template + requires @\libconcept{constructible_from}@ + consteval data_member_options::@\exposid{name-type}@(T&& value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{contents} +with \tcode{u8string(std::forward(value))}. +\end{itemdescr} + +\begin{itemdecl} +template + requires @\libconcept{constructible_from}@ + consteval data_member_options::@\exposid{name-type}@(T&& value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{contents} +with \tcode{string(std::forward(value))}. +\begin{note} +The class \exposid{name-type} allows +the function \tcode{data_member_spec} to accept +an ordinary string literal (or \tcode{string_view}, \tcode{string}, etc.) +or a UTF-8 string literal (or \tcode{u8string_view}, \tcode{u8string}, etc.) +equally well. +\begin{example} +\begin{codeblock} +consteval void fn() { + data_member_options o1 = {.name = "ordinary_literal_encoding"}; + data_member_options o2 = {.name = u8"utf8_encoding"}; +} +\end{codeblock} +\end{example} +\end{note} +\end{itemdescr} + +\indexlibraryglobal{data_member_spec}% +\begin{itemdecl} +consteval info data_member_spec(info type, data_member_options options); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{dealias(type)} represents eitehr an object type or a reference type; +\item + if \tcode{options.name} contains a value, then: + \begin{itemize} + \item + \tcode{holds_alternative(options.name->contents)} is \tcode{true} + and \tcode{get(\brk{}options.name->\brk{}contents)} + contains a valid identifier\iref{lex.name} + that is not a keyword\iref{lex.key} + when interpreted with UTF-8, or + \item + \tcode{holds_alternative(options.name->contents)} is \tcode{true} + and \tcode{get(\newline options.name->contents)} + contains a valid identifier\iref{lex.name} + that is not a keyword\iref{lex.key} + when interpreted with the ordinary literal encoding; + \end{itemize} + \begin{note} + The name corresponds to the spelling of an identifier~token + after phase~6 of translation\iref{lex.phases}. + Lexical constructs like + \grammarterm{universal-character-name}s\iref{lex.universal.char} are not processed + and will cause evaluation to fail. + For example, \tcode{R"(\textbackslash u03B1)"} is an invalid identifier + and is not interpreted as \tcode{"$\alpha$"}. + \end{note} +\item + if \tcode{options.name} does not contain a value, + then \tcode{options.bit_width} contains a value; +\item + if \tcode{options.bit_width} contains a value $V$, then + \begin{itemize} + \item + \tcode{is_integral_type(type) || is_enumeration_type(type)} is \tcode{true}, + \item + \tcode{options.alignment} does not contain a value, + \item + \tcode{options.no_unique_address} is \tcode{false}, and + \item + if $V$ equals \tcode{0}, + then \tcode{options.name} does not contain a value; and + \end{itemize} + \item + if \tcode{options.alignment} contains a value, + it is an alignment value\iref{basic.align} + not less than \tcode{alignment_of(type)}. +\end{itemize} + +\pnum +\returns +A reflection of a data member description +$(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} where +\begin{itemize} +\item + $T$ is the type represented by \tcode{dealias(type)}, +\item + $N$ is either the identifier encoded by \tcode{options.name} + or $\perp$ if \tcode{options.name} does not contain a value, +\item + $A$ is either the alignment value held by \tcode{options.alignment} + or $\perp$ if \tcode{options.alignment} does not contain a value, +\item + $W$ is either the value held by \tcode{options.bit_width} + or $\perp$ if \tcode{options.bit_width} does not contain a value, and +\item + $\mathit{NUA}$ is the value held by \tcode{options.no_unique_address}. +\end{itemize} +\begin{note} +The returned reflection value is primarily useful +in conjunction with \tcode{define_aggregate}; +it can also be queried by certain other functions in \tcode{std::meta} +(e.g., \tcode{type_of}, \tcode{identifier_of}). +\end{note} +\end{itemdescr} + +\indexlibraryglobal{is_data_member_spec}% +\begin{itemdecl} +consteval bool is_data_member_spec(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a data member description. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{define_aggregate}% +\begin{itemdecl} +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info define_aggregate(info class_type, R&& mdescrs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $C$ be the class represented by \tcode{class_type} +and $r_K$ be the $K^\text{th}$ reflection value in \tcode{mdescrs}. +For every $r_K$ in \tcode{mdescrs}, +let $(T_K, N_K, A_K, W_K, \mathit{NUA}_K)$ be +the corresponding data member description represented by $r_K$. + +\pnum +\constantwhen +\begin{itemize} +\item + $C$ is incomplete from every point in the evaluation context; + \begin{note} + $C$ can be a class template specialization + for which there is a reachable definition of the class template. + In this case, + the injected declaration is an explicit specialization. + \end{note} +\item + \tcode{is_data_member_spec($r_K$)} is \tcode{true} for every $r_K$; +\item + \tcode{is_complete_type($T_K$)} is \tcode{true} for every $r_K$; and +\item + for every pair $(r_K, r_L)$ where $K < L$, + if $N_K$ is not $\perp$ and $N_L$ is not $\perp$, + then either: + \begin{itemize} + \item + \tcode{$N_K$ != $N_L$} is \tcode{true} or + \item + \tcode{$N_K$ != u8"_"} is \tcode{true}. + \begin{note} + $C$ can be a class template specialization + for which there is a reachable definition of the class template. + In this case, + the injected declaration is an explicit specialization. + \end{note} + \end{itemize} +\end{itemize} + +\pnum +\effects +Produces an injected declaration $C$\iref{expr.const} +that defines $C$ and has properties as follows: +\begin{itemize} +\item + The target scope of $D$ + is the scope to which $C$ belongs\iref{basic.scope.scope}. +\item + The locus of $D$ + follows immediately after the core constant expression + currently under evaluation. +\item + The characteristic sequence of $D$\iref{expr.const} + is the sequence of reflection values $r_K$. +\item + If $C$ is a specialization of a templated class $T$, + and $C$ is not a local class, + then $D$ is an explicit specialization of $T$. +\item + For each $r_K$, + there is a corresponding entity $M_K$ + belonging to the class cope of $D$ + with the following properties: + \begin{itemize} + \item + If $N_K$ is $\perp$, + $M_K$ is an unnamed bit-field. + Otherwise, $M_K$ is a non-static data member whose name is the identifier + determined by the character seqeunce encoed by $N_K$ in UTF-8. + \item + The type of $M_K$ is $T_K$. + \item + $M_K$ is declared with the attribute \tcode{[[no_unique_address]]} + if and only if $\mathit{NUA}_K$ is \tcode{true}. + \item + If $W_K$ is not $\perp$, + $M_K$ is a bit-field whose width is that value. + Otherwise, $M_K$ is not a bit-field. + \item + If $A_K$ is not $\perp$, + $M_K$ has the \grammarterm{alignment-specifier} \tcode{alignas($A_K$)}. + Otherwise, $M_K$ has no \grammarterm{alignment-specifier}. + \end{itemize} + \item + For every $r_L$ in \tcode{mdescrs} such that $K < L$, + the declaration corresponding to $r_K$ + precedes the declaration corresponding to $r_L$. +\end{itemize} + +\pnum +\returns +\tcode{class_type}. +\end{itemdescr} + +\rSec2[meta.reflection.traits]{Reflection type traits} + +\pnum +Subclause~\ref{meta.reflection.traits} specifies \tcode{consteval} functions to +query the properties of types\iref{meta.unary}, +query the relationships between types\iref{meta.rel}, or +transform types\iref{meta.trans}, +during program translation. +Each \tcode{consteval} function declared in this class +has an associated class template declared elsewhere in this document. + +\pnum +Every function and function template declared in this subclause +has the following conditions +required for a call to that function or function template +to be a constant subexpression\iref{defns.const.subexpr}: +\begin{itemize} +\item + For every parameter \tcode{p} of type \tcode{info}, + \tcode{is_type(p)} is \tcode{true}. +\item + For every parameter \tcode{r} + whose type is constrained on \libconcept{reflection_range}, + \tcode{ranges::\brk{}all_of(\brk{}r, is_type)} is \tcode{true}. +\end{itemize} + +\begin{codeblock} +// associated with \ref{meta.unary.cat}, primary type categories +consteval bool @\libglobal{is_void_type}@(info type); +consteval bool @\libglobal{is_null_pointer_type}@(info type); +consteval bool @\libglobal{is_integral_type}@(info type); +consteval bool @\libglobal{is_floating_point_type}@(info type); +consteval bool @\libglobal{is_array_type}@(info type); +consteval bool @\libglobal{is_pointer_type}@(info type); +consteval bool @\libglobal{is_lvalue_reference_type}@(info type); +consteval bool @\libglobal{is_rvalue_reference_type}@(info type); +consteval bool @\libglobal{is_member_object_pointer_type}@(info type); +consteval bool @\libglobal{is_member_function_pointer_type}@(info type); +consteval bool @\libglobal{is_enum_type}@(info type); +consteval bool @\libglobal{is_union_type}@(info type); +consteval bool @\libglobal{is_class_type}@(info type); +consteval bool @\libglobal{is_function_type}@(info type); +consteval bool @\libglobal{is_reflection_type}@(info type); + +// associated with \ref{meta.unary.comp}, composite type categories +consteval bool @\libglobal{is_reference_type}@(info type); +consteval bool @\libglobal{is_arithmetic_type}@(info type); +consteval bool @\libglobal{is_fundamental_type}@(info type); +consteval bool @\libglobal{is_object_type}@(info type); +consteval bool @\libglobal{is_scalar_type}@(info type); +consteval bool @\libglobal{is_compound_type}@(info type); +consteval bool @\libglobal{is_member_pointer_type}@(info type); + +// associated with \ref{meta.unary.prop}, type properties +consteval bool @\libglobal{is_const_type}@(info type); +consteval bool @\libglobal{is_volatile_type}@(info type); +consteval bool @\libglobal{is_trivially_copyable_type}@(info type); +consteval bool @\libglobal{is_trivially_relocatable_type}@(info type); +consteval bool @\libglobal{is_replaceable_type}@(info type); +consteval bool @\libglobal{is_standard_layout_type}@(info type); +consteval bool @\libglobal{is_empty_type}@(info type); +consteval bool @\libglobal{is_polymorphic_type}@(info type); +consteval bool @\libglobal{is_abstract_type}@(info type); +consteval bool @\libglobal{is_final_type}@(info type); +consteval bool @\libglobal{is_aggregate_type}@(info type); +consteval bool @\libglobal{is_consteval_only_type}@(info type); +consteval bool @\libglobal{is_signed_type}@(info type); +consteval bool @\libglobal{is_unsigned_type}@(info type); +consteval bool @\libglobal{is_bounded_array_type}@(info type); +consteval bool @\libglobal{is_unbounded_array_type}@(info type); +consteval bool @\libglobal{is_scoped_enum_type}@(info type); + +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_constructible_type}@(info type, R&& type_args); +consteval bool @\libglobal{is_default_constructible_type}@(info type); +consteval bool @\libglobal{is_copy_constructible_type}@(info type); +consteval bool @\libglobal{is_move_constructible_type}@(info type); + +consteval bool @\libglobal{is_assignable_type}@(info type_dst, info type_src); +consteval bool @\libglobal{is_copy_assignable_type}@(info type); +consteval bool @\libglobal{is_move_assignable_type}@(info type); + +consteval bool @\libglobal{is_swappable_with_type}@(info type_dst, info type_src); +consteval bool @\libglobal{is_swappable_type}@(info type); + +consteval bool @\libglobal{is_destructible_type}@(info type); + +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_trivially_constructible_type}@(info type, R&& type_args); +consteval bool @\libglobal{is_trivially_default_constructible_type}@(info type); +consteval bool @\libglobal{is_trivially_copy_constructible_type}@(info type); +consteval bool @\libglobal{is_trivially_move_constructible_type}@(info type); + +consteval bool @\libglobal{is_trivially_assignable_type}@(info type_dst, info type_src); +consteval bool @\libglobal{is_trivially_copy_assignable_type}@(info type); +consteval bool @\libglobal{is_trivially_move_assignable_type}@(info type); +consteval bool @\libglobal{is_trivially_destructible_type}@(info type); + +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_nothrow_constructible_type}@(info type, R&& type_args); +consteval bool @\libglobal{is_nothrow_default_constructible_type}@(info type); +consteval bool @\libglobal{is_nothrow_copy_constructible_type}@(info type); +consteval bool @\libglobal{is_nothrow_move_constructible_type}@(info type); + +consteval bool @\libglobal{is_nothrow_assignable_type}@(info type_dst, info type_src); +consteval bool @\libglobal{is_nothrow_copy_assignable_type}@(info type); +consteval bool @\libglobal{is_nothrow_move_assignable_type}@(info type); + +consteval bool @\libglobal{is_nothrow_swappable_with_type}@(info type_dst, info type_src); +consteval bool @\libglobal{is_nothrow_swappable_type}@(info type); + +consteval bool @\libglobal{is_nothrow_destructible_type}@(info type); +consteval bool @\libglobal{is_nothrow_relocatable_type}@(info type); + +consteval bool @\libglobal{is_implicit_lifetime_type}@(info type); + +consteval bool @\libglobal{has_virtual_destructor}@(info type); + +consteval bool @\libglobal{has_unique_object_representations}@(info type); + +consteval bool @\libglobal{reference_constructs_from_temporary}@(info type_dst, info type_src); +consteval bool @\libglobal{reference_converts_from_temporary}@(info type_dst, info type_src); + +// associated with \ref{meta.rel}, type relations +consteval bool @\libglobal{is_same_type}@(info type1, info type2); +consteval bool @\libglobal{is_base_of_type}@(info type_base, info type_derived); +consteval bool @\libglobal{is_virtual_base_of_type}@(info type_base, info type_derived); +consteval bool @\libglobal{is_convertible_type}@(info type_src, info type_dst); +consteval bool @\libglobal{is_nothrow_convertible_type}@(info type_src, info type_dst); +consteval bool @\libglobal{is_layout_compatible_type}@(info type1, info type2); +consteval bool + @\libglobal{is_pointer_interconvertible_base_of_type}@(info type_base, info type_derived); + +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_invocable_type}@(info type, R&& type_args); +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_invocable_r_type}@(info type_result, info type, R&& type_args); + +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_nothrow_invocable_type}@(info type, R&& type_args); +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool + @\libglobal{is_nothrow_invocable_r_type}@(info type_result, info type, R&& type_args); + +// associated with \ref{meta.trans.cv}, const-volatile modifications +consteval info @\libglobal{remove_const}@(info type); +consteval info @\libglobal{remove_volatile}@(info type); +consteval info @\libglobal{remove_cv}@(info type); +consteval info @\libglobal{add_const}@(info type); +consteval info @\libglobal{add_volatile}@(info type); +consteval info @\libglobal{add_cv}@(info type); + +// associated with \ref{meta.trans.ref}, reference modifications +consteval info @\libglobal{remove_reference}@(info type); +consteval info @\libglobal{add_lvalue_reference}@(info type); +consteval info @\libglobal{add_rvalue_reference}@(info type); + +// associated with \ref{meta.trans.sign}, sign modifications +consteval info @\libglobal{make_signed}@(info type); +consteval info @\libglobal{make_unsigned}@(info type); + +// associated with \ref{meta.trans.arr}, array modifications +consteval info @\libglobal{remove_extent}@(info type); +consteval info @\libglobal{remove_all_extents}@(info type); + +// associated with \ref{meta.trans.ptr}, pointer modifications +consteval info @\libglobal{remove_pointer}@(info type); +consteval info @\libglobal{add_pointer}@(info type); + +// associated with \ref{meta.trans.other}, other transformations +consteval info @\libglobal{remove_cvref}@(info type); +consteval info @\libglobal{decay}@(info type); +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info @\libglobal{common_type}@(R&& type_args); +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info @\libglobal{common_reference}@(R&& type_args); +consteval info @\libglobal{underlying_type}@(info type); +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info @\libglobal{invoke_result}@(info type, R&& type_args); +consteval info @\libglobal{unwrap_reference}@(info type); +consteval info @\libglobal{unwrap_ref_decay}@(info type); +\end{codeblock} + +\pnum +Ech function or function template declared above has the following behavior +based on the signature and return type of that function or function template. +\begin{note} +The associated class template need not be instantiated. +\end{note} + +%FIXME: This table looks terrible because the left column is too narrow +%to fit the declarations without wrapping. +\begin{libreqtab2a}{Reflection type traits}{meta.reflection.traits} +\\ \topline +\lhdr{Signature and Return Type} & \rhdr{\Fundescx{Returns}} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Signature and Return Type} & \rhdr{\Fundescx{Returns}} \\ \capsep +\endhead + +\indexlibraryglobal{remove_const}% +\tcode{bool meta::\placeholder{UNARY}(info type);\br +bool meta::\placeholder{UNARY}_type(info type);} & +\tcode{std::\placeholder{UNARY}_v<$T$>}, +where $T$ is the type or type alias represented by \tcode{type} +\\ \rowsep + +\tcode{bool meta::\placeholder{BINARY}(info type);\br +bool meta::\placeholder{BINARY}_type(info type);} & +\tcode{std::\placeholder{BINARY}_v<$\mathit{T1}$, $\mathit{T2}$>}, +where $\mathit{T1}$ and $\mathit{T2}$ are the types or type aliases +represented by \tcode{t1} and \tcode{t2}, respectively +\\ \rowsep + +\tcode{template\br + bool meta::\placeholder{VARIADIC}_type(info type, R\&\& args);} & +\tcode{std::\placeholder{VARIADIC}_v<$T$, $U$...>}, +where $T$ is the type or type alias represented by \tcode{type} +and \tcode{U...} is the pack of types or type aliases +whose elements are represented by the corresponding elements of \tcode{args} +\\ \rowsep + +\tcode{template\br + bool meta::\placeholder{VARIADIC}_type(info t1, info t2, R\&\& args);} & +\tcode{std::\placeholder{VARIADIC}_v<$\mathit{T1}$, $\mathit{T2}$, $U$...>}, +where $\mathit{T1}$ and $\mathit{T2}$ are the types or type aliases +represented by \tcode{t1} and \tcode{t2}, respectively, +and \tcode{$U$...} is the pack of types or type aliases +whose elements are represented by the corresponding elements of \tcode{args} +\\ \rowsep + +\tcode{info meta::\placeholder{UNARY}(info type);\br +info meta::\placeholder{UNARY}(info type);} & +A reflection representing the type denoted by +\tcode{std::\placeholder{UNARY}_t<\brk{}$T$>}, +where $T$ is the type or type alias represented by \tcode{type} +\\ \rowsep + +\tcode{template\br + info meta::\placeholder{VARIADIC}(R\&\& args);} & +A reflection representing the type denoted by +\tcode{std::\placeholder{VARIADIC}_t<$T$...>}, +where \tcode{$T$...} is the pack of types or type aliases +whose elements are represented by the corresponding elements of \tcode{args} +\\ \rowsep + +\tcode{template\br + info meta::\placeholder{VARIADIC}(info type, R\&\& args);} & +A reflection representing the type denoted by +\tcode{std::\placeholder{VARIADIC}_t<$T$, $U$...>}, +where \tcode{$T$} is the type or type alias represented by \tcode{type} +and \tcode{$U$...} is the pack of types or type aliases +whose elements are represented by the corresponding elements of \tcode{args} +\\ +\end{libreqtab2a} + +\pnum +\begin{note} +For those functions or function templates which return a reflection, +that reflection always represents a type and never a type alias. +\end{note} + +\pnum +\begin{note} +If \tcode{t} is a reflection of the type \tcode{int} +and \tcode{u} is a reflection of an alias to the type \tcode{int}, +then \tcode{t == u} is \tcode{false} +but \tcode{is_same_type(t, u)} is \tcode{true}. +Also, \tcode{t == dealias(u)} is \tcode{true}. +\end{note} + +\indexlibraryglobal{rank}% +\begin{itemdecl} +consteval size_t rank(info type); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{rank_v}, +where \tcode{T} is the type represented by \tcode{dealias(type)}. +\end{itemdescr} + +\indexlibraryglobal{extent}% +\begin{itemdecl} +consteval size_t extent(info type, unsigned i = 0); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{extent_v}, +where \tcode{T} is the type represented by \tcode{dealias(type)} +and \tcode{I} is a constant equal to \tcode{i}. +\end{itemdescr} + +\indexlibraryglobal{tuple_size}% +\begin{itemdecl} +consteval size_t tuple_size(info type); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{tuple_size_v}, +where \tcode{T} is the type represented by \tcode{dealias(type)}. +\end{itemdescr} + +\indexlibraryglobal{tuple_element}% +\begin{itemdecl} +consteval info tuple_element(size_t index, info type); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A reflection representing +the type denoted by \tcode{tuple_element_t<$I$, T>}, +where \tcode{T} is th type represented by \tcode{dealias(type)}, +and $I$ is a constant equal to \tcode{index}. +\end{itemdescr} + +\indexlibraryglobal{variant_size}% +\begin{itemdecl} +consteval size_t variant_size(info type); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{variant_size_v}, +where \tcode{T} is the type represented by dealias(type). +\end{itemdescr} + +\indexlibraryglobal{variant_alternative}% +\begin{itemdecl} +consteval info variant_alternative(size_t index, info type); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A reflection representing the type denoted by +\tcode{variant_alternative_t<\brk{}$I$, T>}, +where \tcode{T} is the type represented by \tcode{dealias(type)} +and $I$ is a consant equal to \tcode{index}. +\end{itemdescr} + +\indexlibraryglobal{type_order}% +\begin{itemdecl} +consteval strong_ordering type_order(info t1, info t2); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{type_order_v}, +where \tcode{T1} and \tcode{T2} are the types +represented by \tcode{dealias(t1)} and \tcode{dealias(t2)}, respectively. +\end{itemdescr} + +\rSec2[meta.reflection.annotation]{Annotation reflection} + +\indexlibraryglobal{annotations_of}% +\begin{itemdecl} +consteval vector annotations_of(info item); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{item} represents a +type, +type alias, +variable, +function, +namespace, +enumerator, +direct base class relationship, or +non-static data member. + +%FIXME: it is highly unusual for this subclause to put Let paragraphs after Constant When +\pnum +Let $E$ be +\begin{itemize} +\item + the corresponding \grammarterm{base-specifier} + if \tcode{item} represents a direct base class relationship, +\item + otherwise, the entity represented by \tcode{item}. +\end{itemize} + +\pnum +\returns +A \tcode{vector} containing all of the reflections $R$ +representing each annotation applying to each declaration of $E$ that precedes either +some point in the evaluation context\iref{expr.const} or +a point immediately following the \grammarterm{class-specifier} +of the outermost class for which such a point is in a complete-class context. +For any two reflections $R_1$ and $R_2$ in the returned \tcode{vector}, +if the annotation represented by $R_1$ precedes the annotation represented by $R_2$, +then $R_1$ appears before $R_2$. +If $R_1$ and $R_2$ represent annotations from the same translation unit $T$, +any element in the returned \tcode{vector} between $R_1$ and $R_2$ +represents an annotation from $T$. +\begin{note} +The order in which two annotations appear is otherwise unspecified. +\end{note} +\begin{example} +\begin{codeblock} +[[=1]] void f(); +[[=2, =3]] void g(); +void g [[=4]] (); + +static_assert(annotations_of(^^f).size() == 1); +static_assert(annotations_of(^^g).size() == 3); +static_assert([: constant_of(annotations_of(^^g)[0]) :] == 2); +static_assert(extract(annotations_of(^^g)[1]) == 3); +static_assert(extract(annotations_of(^^g)[2]) == 4); + +struct Option { bool value; }; + +struct C { + [[=Option{true}]] int a; + [[=Option{false}]] int b; +}; + +static_assert(extract