diff --git a/source/compatibility.tex b/source/compatibility.tex index 87878a3075..930cfb5108 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{} 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,23 @@ \end{codeblock} \end{example} +\diffref{dcl.attr.grammar} +\change +New token \tcode{:]}. +\rationale +Required for new features. +\effect +Valid \CppXXIII{} 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 +254,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/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..06ea697150 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,3461 @@ \end{example} \end{itemdescr} +%FIXME: The paper doesn't actually specify that this subclause should exist, +%but I read between the lines and took editorial liberty to create it. +\rSec1[meta.reflection]{Reflection} + +%FIXME: Jens said this should be [meta.syn] +\rSec2[meta.reflection.synop]{General} +\indexheader{meta}% + +\begin{codeblock} +%FIXME: I see the same in with a // see \ref{initializer.list.syn} comment +#include + +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_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); +} +\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} + +%FIXME: I find it stylistically dubious that we don't say that +%this is std::meta::operators; +%we do repeat ranges:: in the itemdecls for ranges stuff. +%Is this actually okay? +%BIG fix needed in lots of places if not. +\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, +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 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 \tcode{\placeholder{R}} be a constant expression of type \tcode{info} +such that \tcode{\placeholder{R} == r} is \tcode{true}. + +\pnum +\constantwhen +\tcode{[: \placeholder{R} :]} is a valid +\grammarterm{splice-expression}\iref{expr.prim.splice}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return reflect_constant([: \placeholder{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 +%FIXME: inconsistent font use for "explicit" between normative wording and note below. +\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 \tcode{explicit}, +\tcode{is_explicit(r)} is still \tcode{false} +because in general +%FIXME: comma +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 +%FIXME: comma +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}% +\begin{itemdecl} +consteval bool is_enumerator(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents an enumerator. +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 a +%FIXME: "an", not "a" +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 +%FIXME: Very wonky note BEFORE the last sentence, inconsistent with the rest of this subclause. +\begin{note} +A specialization of an alias template is a type alias +%FIXME: missing period in note. +\end{note} +. %FIXME: period following note +Otherwise, \tcode{false}. +\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}. + +%FIXME: Why does this not get its own paragraph? Inconsistent! +\pnum +\begin{note} +A template specialization is not a template. +%FIXME: begin example ? Maybe say "For example" at least? +\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 +%FIXME: comma +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 + %FIXME: "computed by" feels weird and unusual, + %especially in a constant evaluation context. + %It seems fine to say "the value of $A$ without such quirks. + Otherwise, $R$ is a reflection representing the value computed by $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} +%FIXME: why are we just dumping this into the wild instead of in \remarks? +\pnum +\tcode{current} is not an addressable function\iref{namespace.std}. + +\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'$)} + %FIXME: comma + where $S'$ is the parent scope of $S$. +\end{itemize} + +%FIXME: Why is this not \remarks? +\pnum +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. + +\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 +%FIXME: 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} +\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)} + %FIXME: comma + 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$ +%FIXME: comma +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} +%FIXME: begin example? The entirety of the note is an example. +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 +%FIXME: comma +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 +%FIXME: grammatically questionable; +%the relationship itself is not a virtual base class. +%but the base class $B$ in that relationship could be a virtual base class +%and the derived class $D$ could be an abstract class. +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 +%FIXME: category error. +%parent_of(r) is not a type, it's an expression. +%Are we trying to say "the type represented by parent_of(r)"? +of type \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})} +%FIXME: "is true" +%FIXME: comma +that \tcode{sizeof(char\&)\brk{} != size_of(\brk{}\reflexpr{char}\&)}. +%FIXME: "is true" +If \tcode{b} represents a direct base class relationship of an empty base class, +then \tcode{size_of(b) > 0}. +%FIXME: "is 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 a non-static data member + that is a bit-field + %FIXME: comma. I believe non-static data members cannot be unnamed bit-fields, + %so the comma would prevent the sentence from suggesting that false reality. + or an unnamed 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}: +%FIXME: does ISO like paragraphs ending in a colon? + +\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} + %FIXME: is this even valid C++? + %I don't think you can just slap noexcept after an identifier ... + that is a direct member of a class \tcode{C} + %FIXME: comma + 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} + %FIXME: same malformedness issue as above. + %FIXME: comma. + 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 +\effects +%FIXME: Why do we normally make a separate paragraph for Let, +%but here we cram it into effects? +Let \tcode{U} be \tcode{remove_cv_t}. +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 (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 +%FIXME: comma. We're not trying to say that temp represents a template and something else. +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 +%FIXME: comma. +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. + %FIXME: what does it mean for evaluation to fail? Constant When violation? + For example, \tcode{R"(\textbackslash u03B1)"} is an invalid identifier + %FIXME: this shouldn't really be a mathematical alpha, + %but we'd need \textalpha or something from {textgreek} to make it work, I think ... + 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} + %FIXME: comma + 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} + +%FIXME: There is no such defined thing as a "consteval function", +%but there is a \tcode{consteval} function! +\pnum +Subclause~\ref{meta.reflection.traits} specifies 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} +%FIXME: better to say "during program translation". +%FIXME: comma woudl be good here because "at compile time" applies to ALL items. +at compile time. +%FIXME: \tcode{consteval} again. +Each 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}% +%FIXME: we have not been using meta:: in any of the item declarations FOR 3000 LINES of TeX +%but NOW we suddenly changed our minds? +%Maybe avoid meta:: for consistency, or use it everywhere above, +%like we do for ranges:: declarations ... +\tcode{bool meta::\placeholder{UNARY}(info type);\br +bool meta::\placeholder{UNARY}_type(info type);} & +%FIXME: Why are we suddenly using std:: in here? +%I don't think we usually do this for type traits ... +\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$...>} +%FIXME: commma +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$...>} +%FIXME: commma +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$...>} +%FIXME: commma +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} +%FIXME: this is obviously an example, not a 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 +%FIXME: why are we suddenly starting to use math symbols for T +%when the previous paragraph did not? +\tcode{tuple_size_v<$T$>} +%FIXME: comma. +where $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 $T$ is th type represented by \tcode{dealias(type)} +%FIXME: comma. +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<$T$>} +%FIXME: comma +where $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$>} +%FIXME: comma +where $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<$\mathit{T1}$, $\mathit{T2}$>}, +where $\mathit{T1}$ and $\mathit{T2}$ are the types +represented by \tcode{dealias(t1)} and \tcode{dealias(t2)}, respectively. +\end{itemdescr} + \rSec1[ratio]{Compile-time rational arithmetic} \rSec2[ratio.general]{General} diff --git a/source/utilities.tex b/source/utilities.tex index ced638f3f7..caae42247e 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -15145,6 +15145,22 @@ \item \tcode{is_trivially_copyable_v} is \tcode{true}. \end{itemize} +\pnum +\mandates +Neither \tcode{To} nor \tcode{From} are consteval-only types\iref{expr.const}. + +\pnum +\constantwhen +\tcode{To}, \tcode{From}, and the types of all subobjects +of \tcode{To} and \tcode{From} are types \tcode{T} such that: +\begin{itemize} +\item \tcode{is_union_v} is \tcode{false}; +\item \tcode{is_pointer_v} is \tcode{false}; +\item \tcode{is_member_pointer_v} is \tcode{false}; +\item \tcode{is_volatile_v} is \tcode{false}; and +\item \tcode{T} has no non-static data members of reference type. +\end{itemize} + \pnum \returns An object of type \tcode{To}. @@ -15179,19 +15195,6 @@ Otherwise, the behavior is erroneous, and the result is as specified above. \end{itemize} The result does not otherwise contain any indeterminate or erroneous values. - -\pnum -\remarks -This function is \keyword{constexpr} if and only if -\tcode{To}, \tcode{From}, and the types of all subobjects -of \tcode{To} and \tcode{From} are types \tcode{T} such that: -\begin{itemize} -\item \tcode{is_union_v} is \tcode{false}; -\item \tcode{is_pointer_v} is \tcode{false}; -\item \tcode{is_member_pointer_v} is \tcode{false}; -\item \tcode{is_volatile_v} is \tcode{false}; and -\item \tcode{T} has no non-static data members of reference type. -\end{itemize} \end{itemdescr} \rSec2[bit.byteswap]{\tcode{byteswap}} diff --git a/tools/check-source.sh b/tools/check-source.sh index 42596cfbb4..6dbfe29204 100755 --- a/tools/check-source.sh +++ b/tools/check-source.sh @@ -97,7 +97,7 @@ grep -n 'unicode{[^}]*[^0-9a-f}][^}]*}' $texfiles | fail 'use lowercase hex digits inside \\unicode' || failed=1 # Use \iref instead of "(\ref", except for subclause ranges -grep -n '.(\\ref' $texfiles | grep -v -- "--" | +grep -n '.(\\ref{' $texfiles | grep -v -- "--" | fail 'use \\iref instead of (\\ref' || failed=1 # Use \xrefc instead of "ISO C x.y.z" @@ -248,7 +248,7 @@ done | fail 'subclause without siblings' || failed=1 for f in $texlibdesc; do sed -n '/begin{itemdescr}/,/end{itemdescr}/{=;p;}' < $f | sed '/^[0-9]\+$/{N;s/\n/:/;}' | sed "s/.*/$f:&/" | - awk -F: '$3 ~ /^\\pnum/ { seenpnum=1; next } $3 ~ /^\\index/ { next } $3 ~ /^\\(constraints|mandates|expects|effects|sync|ensures|returns|throws|complexity|remarks|errors|recommended)/ { if(seenpnum == 0) { print $0 } } { seenpnum=0 }' + awk -F: '$3 ~ /^\\pnum/ { seenpnum=1; next } $3 ~ /^\\index/ { next } $3 ~ /^\\(constraints|mandates|constantwhen|expects|hardexpects|effects|sync|ensures|returns|throws|complexity|remarks|errors|recommended)/ { if(seenpnum == 0) { print $0 } } { seenpnum=0 }' done | fail '\\pnum missing' || failed=1