%!TEX root = std.tex
\rSec0[meta]{Metaprogramming library}

\rSec1[meta.general]{General}

\pnum
This Clause describes metaprogramming facilities.
These facilities are summarized in \tref{meta.summary}.

\begin{libsumtab}{Metaprogramming library summary}{meta.summary}
\ref{intseq}                & Integer sequences    & \tcode{<utility>}      \\ \rowsep
\ref{type.traits}           & Type traits          & \tcode{<type_traits>}  \\ \rowsep
\ref{meta.reflection}       & Reflection           & \tcode{<meta>}         \\ \rowsep
\ref{ratio}                 & Rational arithmetic  & \tcode{<ratio>}        \\
\end{libsumtab}

\rSec1[intseq]{Compile-time integer sequences}

\rSec2[intseq.general]{General}

\pnum
The library provides a class template that can represent an integer sequence.
When used as an argument to a function template the template parameter pack defining the
sequence can be deduced and used in a pack expansion.
\begin{note}
The \tcode{index_sequence} alias template is provided for the common case of
an integer sequence of type \tcode{size_t}; see also \ref{tuple.apply}.
\end{note}

\rSec2[intseq.intseq]{Class template \tcode{integer_sequence}}

\indexlibraryglobal{integer_sequence}%
\indexlibrarymember{value_type}{integer_sequence}%
\begin{codeblock}
namespace std {
  template<class T, T... I> struct integer_sequence {
    using value_type = T;
    static constexpr size_t size() noexcept { return sizeof...(I); }
  };
}
\end{codeblock}

\pnum
\mandates
\tcode{T} is an integer type.

\rSec2[intseq.make]{Alias template \tcode{make_integer_sequence}}

\indexlibraryglobal{make_integer_sequence}%
\begin{itemdecl}
template<class T, T N>
  using make_integer_sequence = integer_sequence<T, @\seebelow{}@>;
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
$\tcode{N} \geq 0$.

\pnum
The alias template
\tcode{make_integer_sequence} denotes a specialization of
\tcode{integer_sequence} with \tcode{N} constant template arguments.
The type \tcode{make_integer_sequence<T, N>} is an alias for the type
\tcode{integer_sequence<T, 0, 1, $\dotsc$, N - 1>}.
\begin{note}
\tcode{make_integer_sequence<int, 0>} is an alias for the type
\tcode{integer_sequence<int>}.
\end{note}
\end{itemdescr}

\rSec2[intseq.binding]{Structured binding support}

\indexlibraryglobal{tuple_size}%
\indexlibraryglobal{tuple_element}%
\begin{itemdecl}
template<class T, T... Values>
  struct tuple_size<integer_sequence<T, Values...>>
    : integral_constant<size_t, sizeof...(Values)> { };

template<size_t I, class T, T... Values>
  struct tuple_element<I, integer_sequence<T, Values...>> {
    using type = T;
  };
template<size_t I, class T, T... Values>
  struct tuple_element<I, const integer_sequence<T, Values...>> {
    using type = T;
  };
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
$\tcode{I} < \tcode{sizeof...(Values)}$.
\end{itemdescr}

\indexlibrarymember{get}{integer_sequence}%
\begin{itemdecl}
template<size_t I, class T, T... Values>
  constexpr T get(integer_sequence<T, Values...>) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
$\tcode{I} < \tcode{sizeof...(Values)}$.

\pnum
\returns
\tcode{Values...[I]}.
\end{itemdescr}

\rSec1[type.traits]{Metaprogramming and type traits}

\rSec2[type.traits.general]{General}

\pnum
Subclause \ref{type.traits} describes components used by \Cpp{} programs, particularly in
templates, to support the widest possible range of types, optimize
template code usage, detect type related user errors, and perform
type inference and transformation at compile time. It includes type
classification traits, type property inspection traits, and type
transformations. The type classification traits describe a complete taxonomy
of all possible \Cpp{} types, and state where in that taxonomy a given
type belongs. The type property inspection traits allow important
characteristics of types or of combinations of types to be inspected. The
type transformations allow certain properties of types to be manipulated.

\pnum
\indextext{signal-safe!type traits}%
All functions specified in \ref{type.traits} are signal-safe\iref{support.signal}.

\rSec2[meta.rqmts]{Requirements}

\pnum
A \defnoldconcept{UnaryTypeTrait} describes a property
of a type. It shall be a class template that takes one template type
argument and, optionally, additional arguments that help define the
property being described. It shall be \oldconcept{DefaultConstructible},
\oldconcept{CopyConstructible},
and publicly and unambiguously derived, directly or indirectly, from
its \defn{base characteristic}, which is
a specialization of the template
\tcode{integral_constant}\iref{meta.help}, with
the arguments to the template \tcode{integral_constant} determined by the
requirements for the particular property being described.
The member names of the base characteristic shall not be hidden and shall be
unambiguously available in the \oldconcept{UnaryTypeTrait}.

\pnum
A \defnoldconcept{BinaryTypeTrait} describes a
relationship between two types. It shall be a class template that
takes two template type arguments and, optionally, additional
arguments that help define the relationship being described. It shall
be \oldconcept{DefaultConstructible}, \oldconcept{CopyConstructible},
and publicly and unambiguously derived, directly or
indirectly, from
its \term{base characteristic}, which is a specialization
of the template
\tcode{integral_constant}\iref{meta.help}, with
the arguments to the template \tcode{integral_constant} determined by the
requirements for the particular relationship being described.
The member names of the base characteristic shall not be hidden and shall be
unambiguously available in the \oldconcept{BinaryTypeTrait}.

\pnum
A \defnoldconcept{TransformationTrait}
modifies a property
of a type. It shall be a class template that takes one
template type argument and, optionally, additional arguments that help
define the modification. It shall declare a publicly accessible nested type
named \tcode{type}, which shall be a synonym for the modified type.

\pnum
Unless otherwise specified,
the behavior of a program that adds specializations
for any of the templates specified in \ref{type.traits}
is undefined.

\pnum
Unless otherwise specified, an incomplete type may be used
to instantiate a template specified in \ref{type.traits}.
The behavior of a program is undefined if
\begin{itemize}
\item
  an instantiation of a template specified in \ref{type.traits}
  directly or indirectly depends on
  an incompletely-defined object type \tcode{T}, and
\item
  that instantiation could yield a different result
  were \tcode{T} hypothetically completed.
\end{itemize}

\rSec2[meta.type.synop]{Header \tcode{<type_traits>} synopsis}

\indexheader{type_traits}%
\begin{codeblock}
// all freestanding
namespace std {
  // \ref{meta.help}, helper class
  template<class T, T v> struct integral_constant;

  template<bool B>
    using @\libglobal{bool_constant}@ = integral_constant<bool, B>;
  using @\libglobal{true_type}@  = bool_constant<true>;
  using @\libglobal{false_type}@ = bool_constant<false>;

  // \ref{meta.unary.cat}, primary type categories
  template<class T> struct is_void;
  template<class T> struct is_null_pointer;
  template<class T> struct is_integral;
  template<class T> struct is_floating_point;
  template<class T> struct is_array;
  template<class T> struct is_pointer;
  template<class T> struct is_lvalue_reference;
  template<class T> struct is_rvalue_reference;
  template<class T> struct is_member_object_pointer;
  template<class T> struct is_member_function_pointer;
  template<class T> struct is_enum;
  template<class T> struct is_union;
  template<class T> struct is_class;
  template<class T> struct is_function;
  template<class T> struct is_reflection;

  // \ref{meta.unary.comp}, composite type categories
  template<class T> struct is_reference;
  template<class T> struct is_arithmetic;
  template<class T> struct is_fundamental;
  template<class T> struct is_object;
  template<class T> struct is_scalar;
  template<class T> struct is_compound;
  template<class T> struct is_member_pointer;

  // \ref{meta.unary.prop}, type properties
  template<class T> struct is_const;
  template<class T> struct is_volatile;
  template<class T> struct is_trivially_copyable;
  template<class T> struct is_standard_layout;
  template<class T> struct is_empty;
  template<class T> struct is_polymorphic;
  template<class T> struct is_abstract;
  template<class T> struct is_final;
  template<class T> struct is_aggregate;

  template<class T> struct is_structural;
  template<class T> struct is_signed;
  template<class T> struct is_unsigned;
  template<class T> struct is_bounded_array;
  template<class T> struct is_unbounded_array;
  template<class T> struct is_scoped_enum;

  template<class T, class... Args> struct is_constructible;
  template<class T> struct is_default_constructible;
  template<class T> struct is_copy_constructible;
  template<class T> struct is_move_constructible;

  template<class T, class U> struct is_assignable;
  template<class T> struct is_copy_assignable;
  template<class T> struct is_move_assignable;

  template<class T, class U> struct is_swappable_with;
  template<class T> struct is_swappable;

  template<class T> struct is_destructible;

  template<class T, class... Args> struct is_trivially_constructible;
  template<class T> struct is_trivially_default_constructible;
  template<class T> struct is_trivially_copy_constructible;
  template<class T> struct is_trivially_move_constructible;

  template<class T, class U> struct is_trivially_assignable;
  template<class T> struct is_trivially_copy_assignable;
  template<class T> struct is_trivially_move_assignable;
  template<class T> struct is_trivially_destructible;

  template<class T, class... Args> struct is_nothrow_constructible;
  template<class T> struct is_nothrow_default_constructible;
  template<class T> struct is_nothrow_copy_constructible;
  template<class T> struct is_nothrow_move_constructible;

  template<class T, class U> struct is_nothrow_assignable;
  template<class T> struct is_nothrow_copy_assignable;
  template<class T> struct is_nothrow_move_assignable;

  template<class T, class U> struct is_nothrow_swappable_with;
  template<class T> struct is_nothrow_swappable;

  template<class T> struct is_nothrow_destructible;

  template<class T> struct is_implicit_lifetime;

  template<class T> struct has_virtual_destructor;

  template<class T> struct has_unique_object_representations;

  template<class T, class U> struct reference_constructs_from_temporary;
  template<class T, class U> struct reference_converts_from_temporary;

  // \ref{meta.unary.prop.query}, type property queries
  template<class T> struct alignment_of;
  template<class T> struct rank;
  template<class T, unsigned I = 0> struct extent;

  // \ref{meta.rel}, type relations
  template<class T, class U> struct is_same;
  template<class Base, class Derived> struct is_base_of;
  template<class Base, class Derived> struct is_virtual_base_of;
  template<class From, class To> struct is_convertible;
  template<class From, class To> struct is_nothrow_convertible;
  template<class T, class U> struct is_layout_compatible;
  template<class Base, class Derived> struct is_pointer_interconvertible_base_of;

  template<class Fn, class... ArgTypes> struct is_invocable;
  template<class R, class Fn, class... ArgTypes> struct is_invocable_r;

  template<class Fn, class... ArgTypes> struct is_nothrow_invocable;
  template<class R, class Fn, class... ArgTypes> struct is_nothrow_invocable_r;

  template<class Fn, class Tuple> struct is_applicable;
  template<class Fn, class Tuple> struct is_nothrow_applicable;

  // \ref{meta.trans.cv}, const-volatile modifications
  template<class T> struct remove_const;
  template<class T> struct remove_volatile;
  template<class T> struct remove_cv;
  template<class T> struct add_const;
  template<class T> struct add_volatile;
  template<class T> struct add_cv;

  template<class T>
    using @\libglobal{remove_const_t}@    = remove_const<T>::type;
  template<class T>
    using @\libglobal{remove_volatile_t}@ = remove_volatile<T>::type;
  template<class T>
    using @\libglobal{remove_cv_t}@       = remove_cv<T>::type;
  template<class T>
    using @\libglobal{add_const_t}@       = add_const<T>::type;
  template<class T>
    using @\libglobal{add_volatile_t}@    = add_volatile<T>::type;
  template<class T>
    using @\libglobal{add_cv_t}@          = add_cv<T>::type;

  // \ref{meta.trans.ref}, reference modifications
  template<class T> struct remove_reference;
  template<class T> struct add_lvalue_reference;
  template<class T> struct add_rvalue_reference;

  template<class T>
    using @\libglobal{remove_reference_t}@     = remove_reference<T>::type;
  template<class T>
    using @\libglobal{add_lvalue_reference_t}@ = add_lvalue_reference<T>::type;
  template<class T>
    using @\libglobal{add_rvalue_reference_t}@ = add_rvalue_reference<T>::type;

  // \ref{meta.trans.sign}, sign modifications
  template<class T> struct make_signed;
  template<class T> struct make_unsigned;

  template<class T>
    using @\libglobal{make_signed_t}@   = make_signed<T>::type;
  template<class T>
    using @\libglobal{make_unsigned_t}@ = make_unsigned<T>::type;

  // \ref{meta.trans.arr}, array modifications
  template<class T> struct remove_extent;
  template<class T> struct remove_all_extents;

  template<class T>
    using @\libglobal{remove_extent_t}@      = remove_extent<T>::type;
  template<class T>
    using @\libglobal{remove_all_extents_t}@ = remove_all_extents<T>::type;

  // \ref{meta.trans.ptr}, pointer modifications
  template<class T> struct remove_pointer;
  template<class T> struct add_pointer;

  template<class T>
    using @\libglobal{remove_pointer_t}@ = remove_pointer<T>::type;
  template<class T>
    using @\libglobal{add_pointer_t}@    = add_pointer<T>::type;

  // \ref{meta.trans.other}, other transformations
  template<class T> struct type_identity;
  template<class T> struct remove_cvref;
  template<class T> struct decay;
  template<bool, class T = void> struct enable_if;
  template<bool, class T, class F> struct conditional;
  template<class... T> struct common_type;
  template<class T, class U, template<class> class TQual, template<class> class UQual>
    struct basic_common_reference { };
  template<class... T> struct common_reference;
  template<class T> struct underlying_type;
  template<class Fn, class... ArgTypes> struct invoke_result;
  template<class Fn, class Tuple> struct apply_result;
  template<class T> struct unwrap_reference;
  template<class T> struct unwrap_ref_decay;

  template<class T>
    using @\libglobal{type_identity_t}@    = type_identity<T>::type;
  template<class T>
    using @\libglobal{remove_cvref_t}@     = remove_cvref<T>::type;
  template<class T>
    using @\libglobal{decay_t}@            = decay<T>::type;
  template<bool B, class T = void>
    using @\libglobal{enable_if_t}@        = enable_if<B, T>::type;
  template<bool B, class T, class F>
    using @\libglobal{conditional_t}@      = conditional<B, T, F>::type;
  template<class... T>
    using @\libglobal{common_type_t}@      = common_type<T...>::type;
  template<class... T>
    using @\libglobal{common_reference_t}@ = common_reference<T...>::type;
  template<class T>
    using @\libglobal{underlying_type_t}@  = underlying_type<T>::type;
  template<class Fn, class... ArgTypes>
    using @\libglobal{invoke_result_t}@    = invoke_result<Fn, ArgTypes...>::type;
  template<class Fn, class Tuple>
    using @\libglobal{apply_result_t}@     = apply_result<Fn, Tuple>::type;
  template<class T>
    using @\libglobal{unwrap_reference_t}@ = unwrap_reference<T>::type;
  template<class T>
    using @\libglobal{unwrap_ref_decay_t}@ = unwrap_ref_decay<T>::type;
  template<class...>
    using @\libglobal{void_t}@             = void;

  // \ref{meta.logical}, logical operator traits
  template<class... B> struct conjunction;
  template<class... B> struct disjunction;
  template<class B> struct negation;

  // \ref{meta.unary.cat}, primary type categories
  template<class T>
    constexpr bool @\libglobal{is_void_v}@ = is_void<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_null_pointer_v}@ = is_null_pointer<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_integral_v}@ = is_integral<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_floating_point_v}@ = is_floating_point<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_array_v}@ = is_array<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_pointer_v}@ = is_pointer<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_lvalue_reference_v}@ = is_lvalue_reference<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_rvalue_reference_v}@ = is_rvalue_reference<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_member_object_pointer_v}@ = is_member_object_pointer<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_member_function_pointer_v}@ = is_member_function_pointer<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_enum_v}@ = is_enum<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_union_v}@ = is_union<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_class_v}@ = is_class<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_function_v}@ = is_function<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_reflection_v}@ = is_reflection<T>::value;

  // \ref{meta.unary.comp}, composite type categories
  template<class T>
    constexpr bool @\libglobal{is_reference_v}@ = is_reference<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_arithmetic_v}@ = is_arithmetic<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_fundamental_v}@ = is_fundamental<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_object_v}@ = is_object<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_scalar_v}@ = is_scalar<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_compound_v}@ = is_compound<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_member_pointer_v}@ = is_member_pointer<T>::value;

  // \ref{meta.unary.prop}, type properties
  template<class T>
    constexpr bool @\libglobal{is_const_v}@ = is_const<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_volatile_v}@ = is_volatile<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_trivially_copyable_v}@ = is_trivially_copyable<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_standard_layout_v}@ = is_standard_layout<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_empty_v}@ = is_empty<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_polymorphic_v}@ = is_polymorphic<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_abstract_v}@ = is_abstract<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_final_v}@ = is_final<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_aggregate_v}@ = is_aggregate<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_structural_v}@ = is_structural<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_signed_v}@ = is_signed<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_unsigned_v}@ = is_unsigned<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_bounded_array_v}@ = is_bounded_array<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_unbounded_array_v}@ = is_unbounded_array<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_scoped_enum_v}@ = is_scoped_enum<T>::value;
  template<class T, class... Args>
    constexpr bool @\libglobal{is_constructible_v}@ = is_constructible<T, Args...>::value;
  template<class T>
    constexpr bool @\libglobal{is_default_constructible_v}@ = is_default_constructible<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_copy_constructible_v}@ = is_copy_constructible<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_move_constructible_v}@ = is_move_constructible<T>::value;
  template<class T, class U>
    constexpr bool @\libglobal{is_assignable_v}@ = is_assignable<T, U>::value;
  template<class T>
    constexpr bool @\libglobal{is_copy_assignable_v}@ = is_copy_assignable<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_move_assignable_v}@ = is_move_assignable<T>::value;
  template<class T, class U>
    constexpr bool @\libglobal{is_swappable_with_v}@ = is_swappable_with<T, U>::value;
  template<class T>
    constexpr bool @\libglobal{is_swappable_v}@ = is_swappable<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_destructible_v}@ = is_destructible<T>::value;
  template<class T, class... Args>
    constexpr bool @\libglobal{is_trivially_constructible_v}@ = is_trivially_constructible<T, Args...>::value;
  template<class T>
    constexpr bool @\libglobal{is_trivially_default_constructible_v}@
      = is_trivially_default_constructible<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_trivially_copy_constructible_v}@ = is_trivially_copy_constructible<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_trivially_move_constructible_v}@ = is_trivially_move_constructible<T>::value;
  template<class T, class U>
    constexpr bool @\libglobal{is_trivially_assignable_v}@ = is_trivially_assignable<T, U>::value;
  template<class T>
    constexpr bool @\libglobal{is_trivially_copy_assignable_v}@ = is_trivially_copy_assignable<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_trivially_move_assignable_v}@ = is_trivially_move_assignable<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_trivially_destructible_v}@ = is_trivially_destructible<T>::value;
  template<class T, class... Args>
    constexpr bool @\libglobal{is_nothrow_constructible_v}@ = is_nothrow_constructible<T, Args...>::value;
  template<class T>
    constexpr bool @\libglobal{is_nothrow_default_constructible_v}@
      = is_nothrow_default_constructible<T>::value;
  template<class T>
    constexpr bool is_nothrow_copy_constructible_v = is_nothrow_copy_constructible<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_nothrow_move_constructible_v}@ = is_nothrow_move_constructible<T>::value;
  template<class T, class U>
    constexpr bool @\libglobal{is_nothrow_assignable_v}@ = is_nothrow_assignable<T, U>::value;
  template<class T>
    constexpr bool @\libglobal{is_nothrow_copy_assignable_v}@ = is_nothrow_copy_assignable<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_nothrow_move_assignable_v}@ = is_nothrow_move_assignable<T>::value;
  template<class T, class U>
    constexpr bool @\libglobal{is_nothrow_swappable_with_v}@ = is_nothrow_swappable_with<T, U>::value;
  template<class T>
    constexpr bool @\libglobal{is_nothrow_swappable_v}@ = is_nothrow_swappable<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_nothrow_destructible_v}@ = is_nothrow_destructible<T>::value;
  template<class T>
    constexpr bool @\libglobal{is_implicit_lifetime_v}@ = is_implicit_lifetime<T>::value;
  template<class T>
    constexpr bool @\libglobal{has_virtual_destructor_v}@ = has_virtual_destructor<T>::value;
  template<class T>
    constexpr bool @\libglobal{has_unique_object_representations_v}@
      = has_unique_object_representations<T>::value;
  template<class T, class U>
    constexpr bool @\libglobal{reference_constructs_from_temporary_v}@
      = reference_constructs_from_temporary<T, U>::value;
  template<class T, class U>
    constexpr bool @\libglobal{reference_converts_from_temporary_v}@
      = reference_converts_from_temporary<T, U>::value;

  // \ref{meta.unary.prop.query}, type property queries
  template<class T>
    constexpr size_t @\libglobal{alignment_of_v}@ = alignment_of<T>::value;
  template<class T>
    constexpr size_t @\libglobal{rank_v}@ = rank<T>::value;
  template<class T, unsigned I = 0>
    constexpr size_t @\libglobal{extent_v}@ = extent<T, I>::value;

  // \ref{meta.rel}, type relations
  template<class T, class U>
    constexpr bool @\libglobal{is_same_v}@ = is_same<T, U>::value;
  template<class Base, class Derived>
    constexpr bool @\libglobal{is_base_of_v}@ = is_base_of<Base, Derived>::value;
  template<class Base, class Derived>
    constexpr bool @\libglobal{is_virtual_base_of_v}@ = is_virtual_base_of<Base, Derived>::value;
  template<class From, class To>
    constexpr bool @\libglobal{is_convertible_v}@ = is_convertible<From, To>::value;
  template<class From, class To>
    constexpr bool @\libglobal{is_nothrow_convertible_v}@ = is_nothrow_convertible<From, To>::value;
  template<class T, class U>
    constexpr bool @\libglobal{is_layout_compatible_v}@ = is_layout_compatible<T, U>::value;
  template<class Base, class Derived>
    constexpr bool @\libglobal{is_pointer_interconvertible_base_of_v}@
      = is_pointer_interconvertible_base_of<Base, Derived>::value;
  template<class Fn, class... ArgTypes>
    constexpr bool @\libglobal{is_invocable_v}@ = is_invocable<Fn, ArgTypes...>::value;
  template<class R, class Fn, class... ArgTypes>
    constexpr bool @\libglobal{is_invocable_r_v}@ = is_invocable_r<R, Fn, ArgTypes...>::value;
  template<class Fn, class... ArgTypes>
    constexpr bool @\libglobal{is_nothrow_invocable_v}@ = is_nothrow_invocable<Fn, ArgTypes...>::value;
  template<class R, class Fn, class... ArgTypes>
    constexpr bool @\libglobal{is_nothrow_invocable_r_v}@ = is_nothrow_invocable_r<R, Fn, ArgTypes...>::value;
  template<class Fn, class Tuple>
    constexpr bool @\libglobal{is_applicable_v}@ = is_applicable<Fn, Tuple>::value;
  template<class Fn, class Tuple>
    constexpr bool @\libglobal{is_nothrow_applicable_v}@ = is_nothrow_applicable<Fn, Tuple>::value;

  // \ref{meta.logical}, logical operator traits
  template<class... B>
    constexpr bool @\libglobal{conjunction_v}@ = conjunction<B...>::value;
  template<class... B>
    constexpr bool @\libglobal{disjunction_v}@ = disjunction<B...>::value;
  template<class B>
    constexpr bool @\libglobal{negation_v}@ = negation<B>::value;

  // \ref{meta.member}, member relationships
  template<class S, class M>
    constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept;
  template<class S1, class S2, class M1, class M2>
    constexpr bool is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept;

  // \ref{meta.const.eval}, constant evaluation context
  constexpr bool is_constant_evaluated() noexcept;
  template<class U = void, class T>
    consteval bool is_within_lifetime(const T*) noexcept;
}
\end{codeblock}

\rSec2[meta.help]{Helper classes}

\indexlibrarymember{value_type}{integral_constant}%
\begin{codeblock}
namespace std {
  template<class T, T v> struct @\libglobal{integral_constant}@ {
    static constexpr T value = v;

    using value_type = T;
    using type = integral_constant<T, v>;

    constexpr operator value_type() const noexcept { return value; }
    constexpr value_type operator()() const noexcept { return value; }
  };
}
\end{codeblock}

\indexlibraryglobal{bool_constant}%
\indexlibraryglobal{true_type}%
\indexlibraryglobal{false_type}%
\pnum
The class template \tcode{integral_constant},
alias template \tcode{bool_constant}, and
its associated \grammarterm{typedef-name}{s}
\tcode{true_type} and \tcode{false_type}
are used as base classes to define
the interface for various type traits.

\rSec2[meta.unary]{Unary type traits}

\rSec3[meta.unary.general]{General}

\pnum
Subclause \ref{meta.unary} contains templates that may be used to query the
properties of a type at compile time.

\pnum
Each of these templates shall be a
\oldconcept{UnaryTypeTrait}\iref{meta.rqmts}
with a base characteristic of
\tcode{true_type} if the corresponding condition is \tcode{true}, otherwise
\tcode{false_type}.

\rSec3[meta.unary.cat]{Primary type categories}

\pnum
The primary type categories specified in \tref{meta.unary.cat}
correspond to the descriptions given in
subclause~\ref{basic.types} of the \Cpp{} standard.

\pnum
For any given type \tcode{T}, the result of applying one of these templates to
\tcode{T} and to \cv{}~\tcode{T} shall yield the same result.

\pnum
\begin{note}
For any given type \tcode{T}, exactly one of the primary type categories
has a \tcode{value} member that evaluates to \tcode{true}.
\end{note}

\begin{libreqtab3e}{Primary type category predicates}{meta.unary.cat}
\\ \topline
\lhdr{Template} &   \chdr{Condition}    &   \rhdr{Comments} \\\capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template} &   \chdr{Condition}    &   \rhdr{Comments} \\ \capsep
\endhead
\indexlibraryglobal{is_void}%
\tcode{template<class T>}\br
 \tcode{struct is_void;}                &
\tcode{T} is \keyword{void}       &   \\ \rowsep
\indexlibraryglobal{is_null_pointer}%
\tcode{template<class T>}\br
 \tcode{struct is_null_pointer;}                &
\tcode{T} is \tcode{nullptr_t}\iref{basic.fundamental}       &   \\ \rowsep
\indexlibraryglobal{is_integral}%
\tcode{template<class T>}\br
 \tcode{struct is_integral;}        &
\tcode{T} is an integral type\iref{basic.fundamental}                 &   \\ \rowsep
\indexlibraryglobal{is_floating_point}%
\tcode{template<class T>}\br
 \tcode{struct is_floating_point;}  &
\tcode{T} is a floating-point type\iref{basic.fundamental}            &   \\ \rowsep
\indexlibraryglobal{is_array}%
\tcode{template<class T>}\br
 \tcode{struct is_array;}           &
\tcode{T} is an array type\iref{basic.compound} of known or unknown extent    &
Class template \tcode{array}\iref{array}
is not an array type.                   \\ \rowsep
\indexlibraryglobal{is_pointer}%
\tcode{template<class T>}\br
 \tcode{struct is_pointer;}         &
\tcode{T} is a pointer type\iref{basic.compound}                      &
Includes pointers to functions
but not pointers to non-static members.                        \\ \rowsep
\indexlibraryglobal{is_lvalue_reference}%
\tcode{template<class T>}\br
 \tcode{struct is_lvalue_reference;}    &
 \tcode{T} is an lvalue reference type\iref{dcl.ref}   &   \\ \rowsep
\indexlibraryglobal{is_rvalue_reference}%
\tcode{template<class T>}\br
 \tcode{struct is_rvalue_reference;}    &
 \tcode{T} is an rvalue reference type\iref{dcl.ref}   &   \\ \rowsep
\indexlibraryglobal{is_member_object_pointer}%
\tcode{template<class T>}\br
 \tcode{struct is_member_object_pointer;}&
 \tcode{T} is a pointer to data member                              &   \\ \rowsep
\indexlibraryglobal{is_member_function_pointer}%
\tcode{template<class T>}\br
 \tcode{struct is_member_function_pointer;}&
\tcode{T} is a pointer to member function                           &   \\ \rowsep
\indexlibraryglobal{is_enum}%
\tcode{template<class T>}\br
 \tcode{struct is_enum;}            &
\tcode{T} is an enumeration type\iref{basic.compound}                 &   \\ \rowsep
\indexlibraryglobal{is_union}%
\tcode{template<class T>}\br
 \tcode{struct is_union;}           &
\tcode{T} is a union type\iref{basic.compound}                        &   \\ \rowsep
\indexlibraryglobal{is_class}%
\tcode{template<class T>}\br
 \tcode{struct is_class;}           &
\tcode{T} is a non-union class type\iref{basic.compound} & \\ \rowsep
\indexlibraryglobal{is_function}%
\tcode{template<class T>}\br
 \tcode{struct is_function;}        &
\tcode{T} is a function type\iref{basic.compound}                     &   \\ \rowsep
\indexlibraryglobal{is_reflection}%
\tcode{template<class T>}\br
 \tcode{struct is_reflection;}        &
\tcode{T} is \tcode{std::meta::info}\iref{basic.fundamental}          &   \\
\end{libreqtab3e}

\rSec3[meta.unary.comp]{Composite type traits}

\pnum
The templates specified in \tref{meta.unary.comp}
provide convenient compositions of the primary type categories,
corresponding to the descriptions given in subclause~\ref{basic.types}.

\pnum
For any given type \tcode{T}, the result of applying one of these templates to
\tcode{T} and to \cv{}~\tcode{T} shall yield the same result.

\begin{libreqtab3b}{Composite type category predicates}{meta.unary.comp}
\\ \topline
\lhdr{Template} &   \chdr{Condition}    &   \rhdr{Comments} \\ \capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template} &   \chdr{Condition}    &   \rhdr{Comments} \\ \capsep
\endhead
\indexlibraryglobal{is_reference}%
\tcode{template<class T>}\br
 \tcode{struct is_reference;}   &
 \tcode{T} is an lvalue reference or an rvalue reference &  \\ \rowsep
\indexlibraryglobal{is_arithmetic}%
\tcode{template<class T>}\br
 \tcode{struct is_arithmetic;}          &
 \tcode{T} is an arithmetic type\iref{basic.fundamental}              &   \\ \rowsep
\indexlibraryglobal{is_fundamental}%
\tcode{template<class T>}\br
 \tcode{struct is_fundamental;}         &
 \tcode{T} is a fundamental type\iref{basic.fundamental}              &   \\ \rowsep
\indexlibraryglobal{is_object}%
\tcode{template<class T>}\br
 \tcode{struct is_object;}              &
 \tcode{T} is an object type\iref{term.object.type}                    &   \\ \rowsep
\indexlibraryglobal{is_scalar}%
\tcode{template<class T>}\br
 \tcode{struct is_scalar;}              &
 \tcode{T} is a scalar type\iref{term.scalar.type}                       &   \\ \rowsep
\indexlibraryglobal{is_compound}%
\tcode{template<class T>}\br
 \tcode{struct is_compound;}            &
 \tcode{T} is a compound type\iref{basic.compound}                        &   \\ \rowsep
\indexlibraryglobal{is_member_pointer}%
\tcode{template<class T>}\br
 \tcode{struct is_member_pointer;}      &
 \tcode{T} is a pointer-to-member type\iref{basic.compound}               &   \\
\end{libreqtab3b}

\rSec3[meta.unary.prop]{Type properties}

\pnum
The templates specified in \tref{meta.unary.prop}
provide access to some of the more important properties of types.

\pnum
It is unspecified whether the library defines any full or partial
specializations of any of these templates.

\pnum
For all of the class templates \tcode{X} declared in this subclause,
instantiating that template with a template-argument that is a class
template specialization may result in the implicit instantiation of
the template argument if and only if the semantics of \tcode{X} require that
the argument is a complete type.

\pnum
For the purpose of defining the templates in this subclause,
a function call expression \tcode{declval<T>()} for any type \tcode{T}
is considered to be a trivial\iref{term.trivial.type,special} function call
that is not an odr-use\iref{term.odr.use} of \tcode{declval}
in the context of the corresponding definition
notwithstanding the restrictions of~\ref{declval}.

\pnum
For the purpose of defining the templates in this subclause,
let \tcode{\placeholdernc{VAL}<T>} for some type \tcode{T} be
an expression defined as follows:
\begin{itemize}
\item
If \tcode{T} is a reference or function type,
\tcode{\placeholdernc{VAL}<T>} is an expression
with the same type and value category as \tcode{declval<T>()}.
\item
Otherwise, \tcode{\placeholdernc{VAL}<T>} is a prvalue
that initially has type \tcode{T}.
\begin{note}
If \tcode{T} is cv-qualified,
the cv-qualification is subject to adjustment\iref{expr.type}.
\end{note}
\end{itemize}

\begin{libreqtab3b}{Type property predicates}{meta.unary.prop}
\\ \topline
\lhdr{Template} &   \chdr{Condition}    &   \rhdr{Preconditions}    \\ \capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template} &   \chdr{Condition}    &   \rhdr{Preconditions}    \\ \capsep
\endhead

\indexlibraryglobal{is_const}%
\tcode{template<class T>}\br
 \tcode{struct is_const;}               &
 \tcode{T} is const-qualified\iref{basic.type.qualifier}                  &   \\ \rowsep

\indexlibraryglobal{is_volatile}%
\tcode{template<class T>}\br
 \tcode{struct is_volatile;}            &
 \tcode{T} is volatile-qualified\iref{basic.type.qualifier}                   &   \\ \rowsep


\indexlibraryglobal{is_trivially_copyable}%
\tcode{template<class T>}\br
 \tcode{struct is_trivially_copyable;}      &
 \tcode{T} is a trivially copyable type\iref{term.trivially.copyable.type} &
 \tcode{remove_all_extents_t<T>} shall be a complete type or
 \cv{}~\keyword{void}.                               \\ \rowsep

\indexlibraryglobal{is_standard_layout}%
\tcode{template<class T>}\br
 \tcode{struct is_standard_layout;}                 &
 \tcode{T} is a standard-layout type\iref{term.standard.layout.type}   &
 \tcode{remove_all_extents_t<T>} shall be a complete
 type or \cv{}~\keyword{void}.                \\ \rowsep

\indexlibrary{\idxcode{is_empty}!class}%
\tcode{template<class T>}\br
 \tcode{struct is_empty;}               &
 \tcode{T} is a class type, but not a union type, with no non-static data
 members other than subobjects of zero size, no virtual member functions,
 no virtual base classes, and no base class \tcode{B} for
 which \tcode{is_empty_v<B>} is \tcode{false}. &
 If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type.                               \\ \rowsep

\indexlibraryglobal{is_polymorphic}%
\tcode{template<class T>}\br
 \tcode{struct is_polymorphic;}         &
 \tcode{T} is a polymorphic class\iref{class.virtual}                             &
 If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type.                \\ \rowsep

\indexlibraryglobal{is_abstract}%
\tcode{template<class T>}\br
 \tcode{struct is_abstract;}            &
 \tcode{T} is an abstract class\iref{class.abstract}                              &
 If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type.                \\ \rowsep

\indexlibraryglobal{is_final}%
\tcode{template<class T>}\br
 \tcode{struct is_final;}               &
 \tcode{T} is a class type marked with the \grammarterm{class-property-specifier}
 \tcode{final}\iref{class.pre}.
\begin{tailnote}
A union is a class type that
 can be marked with \tcode{final}.
\end{tailnote}
&
 If \tcode{T} is a class type, \tcode{T} shall be a complete type.                          \\ \rowsep

\indexlibraryglobal{is_aggregate}%
\tcode{template<class T>}\br
  \tcode{struct is_aggregate;}           &
 \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_structural}%
\tcode{template<class T>}\br
  \tcode{struct is_structural;}           &
 \tcode{T} is a structural type\iref{temp.param} &
 \tcode{remove_all_extents_t<T>} shall be a complete type or \cv~\keyword{void}.        \\ \rowsep

\indexlibrary{\idxcode{is_signed}!class}%
\tcode{template<class T>}\br
  \tcode{struct is_signed;}              &
  If \tcode{is_arithmetic_v<T>} is \tcode{true}, the same result as
  \tcode{T(-1) < T(0)};
  otherwise, \tcode{false}   &   \\  \rowsep

\indexlibraryglobal{is_unsigned}%
\tcode{template<class T>}\br
  \tcode{struct is_unsigned;}            &
  If \tcode{is_arithmetic_v<T>} is \tcode{true}, the same result as
  \tcode{T(0) < T(-1)};
  otherwise, \tcode{false}   &   \\  \rowsep

\indexlibraryglobal{is_bounded_array}%
\tcode{template<class T>}\br
  \tcode{struct is_bounded_array;}       &
  \tcode{T} is an array type of known bound\iref{dcl.array}
                             &   \\  \rowsep

\indexlibraryglobal{is_unbounded_array}%
\tcode{template<class T>}\br
  \tcode{struct is_unbounded_array;}     &
  \tcode{T} is an array type of unknown bound\iref{dcl.array}
                             &   \\  \rowsep

\indexlibraryglobal{is_scoped_enum}%
\tcode{template<class T>}\br
  \tcode{struct is_scoped_enum;}     &
  \tcode{T} is a scoped enumeration\iref{dcl.enum}
                             &   \\  \rowsep

\indexlibraryglobal{is_constructible}%
\tcode{template<class T, class... Args>}\br
 \tcode{struct is_constructible;}   &
 For a function type \tcode{T} or
 for a \cv{}~\keyword{void} type \tcode{T},
 \tcode{is_constructible_v<T, Args...>} is \tcode{false},
 otherwise \seebelow                &
 \tcode{T} and all types in the template parameter pack \tcode{Args}
 shall be complete types, \cv{}~\keyword{void},
 or arrays of unknown bound.  \\ \rowsep

\indexlibraryglobal{is_default_constructible}%
\tcode{template<class T>}\br
  \tcode{struct is_default_constructible;} &
  \tcode{is_constructible_v<T>} is \tcode{true}. &
  \tcode{T} shall be a complete type, \cv{}~\keyword{void},
  or an array of unknown bound. \\ \rowsep

\indexlibraryglobal{is_copy_constructible}%
\tcode{template<class T>}\br
  \tcode{struct is_copy_constructible;} &
  For a referenceable type \tcode{T}\iref{defns.referenceable}, the same result as
  \tcode{is_constructible_v<T, const T\&>}, otherwise \tcode{false}. &
  \tcode{T} shall be a complete type, \cv{}~\keyword{void},
  or an array of unknown bound. \\ \rowsep

\indexlibraryglobal{is_move_constructible}%
\tcode{template<class T>}\br
  \tcode{struct is_move_constructible;} &
  For a referenceable type \tcode{T}, the same result as
  \tcode{is_constructible_v<T, T\&\&>}, otherwise \tcode{false}. &
  \tcode{T} shall be a complete type, \cv{}~\keyword{void},
  or an array of unknown bound. \\ \rowsep

\indexlibraryglobal{is_assignable}%
\tcode{template<class T, class U>}\br
  \tcode{struct is_assignable;} &
  The expression \tcode{declval<T>() =} \tcode{declval<U>()} is well-formed
  when treated as an unevaluated
  operand\iref{term.unevaluated.operand}. Access checking is performed as if in a context
  unrelated to \tcode{T} and \tcode{U}. Only the validity of the immediate context
  of the assignment expression is considered.
\begin{tailnote}
The compilation of the
  expression can result in side effects such as the instantiation of class template
  specializations and function template specializations, the generation of
  implicitly-defined functions, and so on. Such side effects are not in the ``immediate
  context'' and can result in the program being ill-formed.
\end{tailnote}
&
  \tcode{T} and \tcode{U} shall be complete types, \cv{}~\keyword{void},
  or arrays of unknown bound. \\ \rowsep

\indexlibraryglobal{is_copy_assignable}%
\tcode{template<class T>}\br
  \tcode{struct is_copy_assignable;} &
  For a referenceable type \tcode{T}, the same result as
  \tcode{is_assignable_v<T\&, const T\&>}, otherwise \tcode{false}. &
  \tcode{T} shall be a complete type, \cv{}~\keyword{void},
  or an array of unknown bound. \\ \rowsep

\indexlibraryglobal{is_move_assignable}%
\tcode{template<class T>}\br
  \tcode{struct is_move_assignable;} &
  For a referenceable type \tcode{T}, the same result as
  \tcode{is_assignable_v<T\&, T\&\&>}, otherwise \tcode{false}. &
  \tcode{T} shall be a complete type, \cv{}~\keyword{void},
  or an array of unknown bound. \\ \rowsep

\indexlibraryglobal{is_swappable_with}%
\tcode{template<class T, class U>}\br
  \tcode{struct is_swappable_with;} &
  The expressions \tcode{swap(declval<T>(), declval<U>())} and
  \tcode{swap(declval<U>(), declval<T>())} are each well-formed
  when treated as an unevaluated operand\iref{term.unevaluated.operand}
  in an overload-resolution context
  for swappable values\iref{swappable.requirements}.
  Access checking is performed as if in a context
  unrelated to \tcode{T} and \tcode{U}.
  Only the validity of the immediate context
  of the \tcode{swap} expressions is considered.
  \begin{tailnote}
  The compilation of the expressions can result in side effects
  such as the instantiation of class template specializations and
  function template specializations,
  the generation of implicitly-defined functions, and so on.
  Such side effects are not in the ``immediate context'' and
  can result in the program being ill-formed.
  \end{tailnote}
&
  \tcode{T} and \tcode{U} shall be complete types,
  \cv{}~\keyword{void}, or
  arrays of unknown bound.  \\ \rowsep

\indexlibraryglobal{is_swappable}%
\tcode{template<class T>}\br
  \tcode{struct is_swappable;} &
  For a referenceable type \tcode{T},
  the same result as \tcode{is_swappable_with_v<T\&, T\&>},
  otherwise \tcode{false}. &
  \tcode{T} shall be a complete type,
  \cv{}~\keyword{void}, or
  an array of unknown bound. \\ \rowsep

\indexlibraryglobal{is_destructible}%
\tcode{template<class T>}\br
  \tcode{struct is_destructible;} &
  Either \tcode{T} is a reference type,
  or \tcode{T} is a complete object type
  for which the expression
  \tcode{declval<U\&>().\~U()}
  is well-formed
  when treated as an unevaluated operand\iref{term.unevaluated.operand},
  where \tcode{U} is
  \tcode{remove_all_extents_t<T>}. &
  \tcode{T} shall be a complete type, \cv{}~\keyword{void},
  or an array of unknown bound. \\ \rowsep

\indexlibraryglobal{is_trivially_constructible}%
\tcode{template<class T, class... Args>}\br
  \keyword{struct}\br
  \tcode{is_trivially_constructible;} &
  \tcode{is_constructible_v<T,}\br
  \tcode{Args...>} is \tcode{true} and the variable
  definition for \tcode{is_constructible}, as defined below, is known to call
  no operation that is not trivial\iref{term.trivial.type,special}. &
  \tcode{T} and all types in the template parameter pack \tcode{Args} shall be complete types,
  \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep

\indexlibraryglobal{is_trivially_default_constructible}%
\tcode{template<class T>}\br
 \tcode{struct is_trivially_default_constructible;} &
 \tcode{is_trivially_constructible_v<T>} is \tcode{true}. &
 \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown
 bound.                \\ \rowsep

\indexlibraryglobal{is_trivially_copy_constructible}%
\tcode{template<class T>}\br
 \tcode{struct is_trivially_copy_constructible;}      &
  For a referenceable type \tcode{T}, the same result as
 \tcode{is_trivially_constructible_v<T, const T\&>}, otherwise \tcode{false}. &
  \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown
 bound.                \\ \rowsep

\indexlibraryglobal{is_trivially_move_constructible}%
\tcode{template<class T>}\br
 \tcode{struct is_trivially_move_constructible;}      &
  For a referenceable type \tcode{T}, the same result as
 \tcode{is_trivially_constructible_v<T, T\&\&>}, otherwise \tcode{false}. &
  \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown
 bound.                \\ \rowsep

\indexlibraryglobal{is_trivially_assignable}%
\tcode{template<class T, class U>}\br
  \tcode{struct is_trivially_assignable;} &
  \tcode{is_assignable_v<T, U>} is \tcode{true} and the assignment, as defined by
  \tcode{is_assignable}, is known to call no operation that is not
  trivial\iref{term.trivial.type,special}. &
  \tcode{T} and \tcode{U} shall be complete types, \cv{}~\keyword{void},
  or arrays of unknown bound. \\ \rowsep

\indexlibraryglobal{is_trivially_copy_assignable}%
\tcode{template<class T>}\br
 \tcode{struct is_trivially_copy_assignable;} &
  For a referenceable type \tcode{T}, the same result as
 \tcode{is_trivially_assignable_v<T\&, const T\&>}, otherwise \tcode{false}. &
 \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown
 bound.                \\ \rowsep

\indexlibraryglobal{is_trivially_move_assignable}%
\tcode{template<class T>}\br
 \tcode{struct is_trivially_move_assignable;} &
  For a referenceable type \tcode{T}, the same result as
 \tcode{is_trivially_assignable_v<T\&, T\&\&>}, otherwise \tcode{false}. &
 \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown bound.                \\ \rowsep

\indexlibraryglobal{is_trivially_destructible}%
\tcode{template<class T>}\br
 \tcode{struct is_trivially_destructible;} &
 \tcode{is_destructible_v<T>} is \tcode{true} and
 \tcode{remove_all_extents_t<T>} is either a non-class type or
 a class type with a trivial destructor. &
 \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown
 bound.                \\ \rowsep

\indexlibraryglobal{is_nothrow_constructible}%
\tcode{template<class T, class... Args>}\br
 \tcode{struct is_nothrow_constructible;}   &
 \tcode{is_constructible_v<T,} \tcode{ Args...>} is \tcode{true}
 and the
 variable definition for \tcode{is_constructible}, as defined below, is known not to
 throw any exceptions\iref{expr.unary.noexcept}.
 &
 \tcode{T} and all types in the template parameter pack \tcode{Args}
 shall be complete types, \cv{}~\keyword{void},
 or arrays of unknown bound.  \\ \rowsep

\indexlibraryglobal{is_nothrow_default_constructible}%
\tcode{template<class T>}\br
 \tcode{struct is_nothrow_default_constructible;} &
 \tcode{is_nothrow_constructible_v<T>} is \tcode{true}.  &
 \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown
 bound.                \\ \rowsep

\indexlibraryglobal{is_nothrow_copy_constructible}%
\tcode{template<class T>}\br
 \tcode{struct is_nothrow_copy_constructible;}      &
  For a referenceable type \tcode{T}, the same result as
 \tcode{is_nothrow_constructible_v<T, const T\&>}, otherwise \tcode{false}. &
 \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown
 bound.                \\ \rowsep

\indexlibraryglobal{is_nothrow_move_constructible}%
\tcode{template<class T>}\br
 \tcode{struct is_nothrow_move_constructible;}      &
  For a referenceable type \tcode{T}, the same result as
 \tcode{is_nothrow_constructible_v<T, T\&\&>}, otherwise \tcode{false}. &
 \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown bound.                \\ \rowsep

\indexlibraryglobal{is_nothrow_assignable}%
\tcode{template<class T, class U>}\br
  \tcode{struct is_nothrow_assignable;} &
  \tcode{is_assignable_v<T, U>} is \tcode{true} and the assignment is known not to
  throw any exceptions\iref{expr.unary.noexcept}. &
  \tcode{T} and \tcode{U} shall be complete types, \cv{}~\keyword{void},
  or arrays of unknown bound. \\ \rowsep

\indexlibraryglobal{is_nothrow_copy_assignable}%
\tcode{template<class T>}\br
 \tcode{struct is_nothrow_copy_assignable;} &
  For a referenceable type \tcode{T}, the same result as
 \tcode{is_nothrow_assignable_v<T\&, const T\&>}, otherwise \tcode{false}. &
 \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown
 bound.                \\ \rowsep

\indexlibraryglobal{is_nothrow_move_assignable}%
\tcode{template<class T>}\br
  \tcode{struct is_nothrow_move_assignable;} &
  For a referenceable type \tcode{T}, the same result as
  \tcode{is_nothrow_assignable_v<T\&, T\&\&>}, otherwise \tcode{false}. &
 \tcode{T} shall be a complete type,
 \cv{}~\keyword{void}, or an array of unknown
 bound.                \\ \rowsep

\indexlibraryglobal{is_nothrow_swappable_with}%
\tcode{template<class T, class U>}\br
  \tcode{struct is_nothrow_swappable_with;} &
  \tcode{is_swappable_with_v<T, U>} is \tcode{true} and
  each \tcode{swap} expression of the definition of
  \tcode{is_swappable_with<T, U>} is known not to throw
  any exceptions\iref{expr.unary.noexcept}. &
  \tcode{T} and \tcode{U} shall be complete types,
  \cv{}~\keyword{void}, or
  arrays of unknown bound. \\ \rowsep

\indexlibraryglobal{is_nothrow_swappable}%
\tcode{template<class T>}\br
  \tcode{struct is_nothrow_swappable;} &
  For a referenceable type \tcode{T},
  the same result as \tcode{is_nothrow_swappable_with_v<T\&, T\&>},
  otherwise \tcode{false}. &
  \tcode{T} shall be a complete type,
  \cv{}~\keyword{void}, or
  an array of unknown bound. \\ \rowsep

\indexlibraryglobal{is_nothrow_destructible}%
\tcode{template<class T>}\br
  \tcode{struct is_nothrow_destructible;} &
  \tcode{is_destructible_v<T>} is \tcode{true} and the indicated destructor is known
  not to throw any exceptions\iref{expr.unary.noexcept}. &
  \tcode{T} shall be a complete type,
  \cv{}~\keyword{void}, or an array of unknown
  bound.                \\ \rowsep

\indexlibraryglobal{is_implicit_lifetime}%
\tcode{template<class T>}\br
  \tcode{struct is_implicit_lifetime;} &
  \tcode{T} is an implicit-lifetime type\iref{term.implicit.lifetime.type}. &
  \tcode{T} shall be an array type,
  a complete type, or \cv{}~\keyword{void}.  \\ \rowsep

\indexlibraryglobal{has_virtual_destructor}%
\tcode{template<class T>}\br
 \tcode{struct has_virtual_destructor;} &
 \tcode{T} has a virtual destructor\iref{class.dtor} &
 If \tcode{T} is a non-union class type, \tcode{T} shall be a complete type.                \\ \rowsep

\indexlibraryglobal{has_unique_object_representations}%
\tcode{template<class T>}\br
  \tcode{struct has_unique_object_representations;} &
  For an array type \tcode{T}, the same result as
  \tcode{has_unique_object_representations_v<remove_all_extents_t<T>>},
  otherwise \seebelow. &
  \tcode{remove_all_extents_t<T>} shall be a complete type or
  \cv{}~\keyword{void}.  \\ \rowsep

\indexlibraryglobal{reference_constructs_from_temporary}%
\tcode{template<class T, class U>}\br
  \tcode{struct reference_constructs_from_temporary;} &
  \tcode{T} is a reference type, and
  the initialization \tcode{T t(\exposidnc{VAL}<U>);} is
  well-formed and binds \tcode{t} to
  a temporary object whose lifetime is extended\iref{class.temporary}.
  The full-expression of the variable initialization is
  treated as an unevaluated operand\iref{expr.context}.
  Access checking is performed as if in
  a context unrelated to \tcode{T} and \tcode{U}.
  Only the validity of the immediate context of
  the variable initialization is considered.
  \begin{tailnote}
  The initialization can result in effects such as
  the instantiation of class template specializations and
  function template specializations,
  the generation of implicitly-defined functions, and so on.
  Such effects are not in the ``immediate context'' and
  can result in the program being ill-formed.
  \end{tailnote}
&
  \tcode{T} and \tcode{U} shall be
  complete types, \cv{}~\keyword{void}, or arrays of unknown bound.  \\ \rowsep

\indexlibraryglobal{reference_converts_from_temporary}%
\tcode{template<class T, class U>}\br
  \tcode{struct reference_converts_from_temporary;} &
  \tcode{T} is a reference type, and
  the initialization \tcode{T t = \exposidnc{VAL}<U>;}
  is well-formed and binds \tcode{t} to
  a temporary object whose lifetime is extended\iref{class.temporary}.
  The full-expression of the variable initialization is
  treated as an unevaluated operand\iref{expr.context}.
  Access checking is performed as if in
  a context unrelated to \tcode{T} and \tcode{U}.
  Only the validity of the immediate context of
  the variable initialization is considered.
  \begin{tailnote}
  The initialization can result in effects such as
  the instantiation of class template specializations and
  function template specializations,
  the generation of implicitly-defined functions, and so on.
  Such effects are not in the ``immediate context'' and
  can result in the program being ill-formed.
  \end{tailnote}
&
  \tcode{T} and \tcode{U} shall be
  complete types, \cv{}~\keyword{void}, or arrays of unknown bound.  \\ \rowsep

\end{libreqtab3b}

\pnum
\begin{example}
\begin{codeblock}
is_const_v<const volatile int>      // \tcode{true}
is_const_v<const int*>              // \tcode{false}
is_const_v<const int&>              // \tcode{false}
is_const_v<int[3]>                  // \tcode{false}
is_const_v<const int[3]>            // \tcode{true}
\end{codeblock}
\end{example}

\pnum
\begin{example}
\begin{codeblock}
remove_const_t<const volatile int>  // \tcode{volatile int}
remove_const_t<const int* const>    // \tcode{const int*}
remove_const_t<const int&>          // \tcode{const int\&}
remove_const_t<const int[3]>        // \tcode{int[3]}
\end{codeblock}
\end{example}

\pnum
\begin{example}
\begin{codeblock}
// Given:
struct P final { };
union U1 { };
union U2 final { };

// the following assertions hold:
static_assert(!is_final_v<int>);
static_assert(is_final_v<P>);
static_assert(!is_final_v<U1>);
static_assert(is_final_v<U2>);
\end{codeblock}
\end{example}

\indexlibraryglobal{is_constructible}%
\pnum
The predicate condition for a template specialization
\tcode{is_constructible<T, Args...>} shall be satisfied if and only if the
following variable definition would be well-formed for some invented variable \tcode{t}:

\begin{codeblock}
T t(declval<Args>()...);
\end{codeblock}

\begin{note}
These tokens are never interpreted as a function declaration.
\end{note}
The full-expression of the variable initialization is
treated as an unevaluated operand\iref{expr.context}.
Access checking is performed as if in a context unrelated to \tcode{T}
and any of the \tcode{Args}. Only the validity of the immediate context of the
variable initialization is considered.
\begin{note}
The evaluation of the
initialization can result in side effects such as the instantiation of class
template specializations and function template specializations, the generation
of implicitly-defined functions, and so on. Such side effects are not in the
``immediate context'' and can result in the program being ill-formed.
\end{note}

\indexlibraryglobal{has_unique_object_representations}%
\pnum
The predicate condition for a template specialization
\tcode{has_unique_object_representations<T>}
shall be satisfied if and only if
\begin{itemize}
\item \tcode{T} is trivially copyable, and
\item any two objects of type \tcode{T} with the same value
have the same object representation, where
\begin{itemize}
\item two objects of array or non-union class type are considered to have the same value
if their respective sequences of direct subobjects have the same values, and
\item two objects of union type are considered to have the same value
if they have the same active member and the corresponding members have the same value.
\end{itemize}
\end{itemize}
The set of scalar types for which this condition holds is
\impldef{which scalar types have unique object representations}.
\begin{note}
If a type has padding bits, the condition does not hold;
otherwise, the condition holds true for integral types.
\end{note}

\rSec2[meta.unary.prop.query]{Type property queries}

\pnum
The templates specified in \tref{meta.unary.prop.query}
may be used to query properties of types at compile time.

\begin{libreqtab2a}{Type property queries}{meta.unary.prop.query}
\\ \topline
\lhdr{Template} &   \rhdr{Value}    \\ \capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template} &   \rhdr{Value}    \\ \capsep
\endhead

\indexlibraryglobal{alignment_of}%
\tcode{template<class T>\br
 struct alignment_of;}      &
 \tcode{alignof(T)}.\br
 \mandates
 \tcode{alignof(T)} is a valid expression\iref{expr.alignof}  \\  \rowsep

\indexlibraryglobal{rank}%
\tcode{template<class T>\br
 struct rank;}      &
 If \tcode{T} is an array type, an integer value representing
 the number of dimensions of \tcode{T}; otherwise, 0. \\    \rowsep

\indexlibraryglobal{extent}%
\tcode{template<class T,\br
 unsigned I = 0>\br
 struct extent;}        &
 If \tcode{T} is not an array type, or if it has rank less
 than or equal to \tcode{I}, or if \tcode{I} is 0 and \tcode{T}
 has type ``array of unknown bound of \tcode{U}'', then
 0; otherwise, the bound\iref{dcl.array} of the $\tcode{I}^\text{th}$ dimension of
\tcode{T}, where indexing of \tcode{I} is zero-based \\
\end{libreqtab2a}

\pnum
Each of these templates shall be a \oldconcept{UnaryTypeTrait}\iref{meta.rqmts} with a
base characteristic of \tcode{integral_constant<size_t, Value>}.

\pnum
\begin{example}
\begin{codeblock}
// the following assertions hold:
static_assert(rank_v<int> == 0);
static_assert(rank_v<int[2]> == 1);
static_assert(rank_v<int[][4]> == 2);
\end{codeblock}
\end{example}

\pnum
\begin{example}
\begin{codeblock}
// the following assertions hold:
static_assert(extent_v<int> == 0);
static_assert(extent_v<int[2]> == 2);
static_assert(extent_v<int[2][4]> == 2);
static_assert(extent_v<int[][4]> == 0);
static_assert(extent_v<int, 1> == 0);
static_assert(extent_v<int[2], 1> == 0);
static_assert(extent_v<int[2][4], 1> == 4);
static_assert(extent_v<int[][4], 1> == 4);
\end{codeblock}
\end{example}

\rSec2[meta.rel]{Relationships between types}

\pnum
The templates specified in \tref{meta.rel}
may be used to query relationships between types at compile time.

\pnum
Each of these templates shall be a
\oldconcept{BinaryTypeTrait}\iref{meta.rqmts}
with a base characteristic of
\tcode{true_type} if the corresponding condition is true, otherwise
\tcode{false_type}.

\pnum
Let \tcode{\placeholdernc{ELEMS-OF}(T)} be the parameter pack
\tcode{get<\exposid{N}>(declval<T>())}, where \exposid{N} is the pack of
\tcode{size_t} template arguments of the specialization of
\tcode{index_sequence} denoted by
\tcode{make_index_sequence<tuple_size_v<remove_reference_t<T>>>}.

\begin{libreqtab3f}{Type relationship predicates}{meta.rel}
\\ \topline
\lhdr{Template} &   \chdr{Condition}    &   \rhdr{Comments} \\ \capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template} &   \chdr{Condition}    &   \rhdr{Comments} \\ \capsep
\endhead
\tcode{template<class T, class U>}\br
 \tcode{struct is_same;}                    &
 \tcode{T} and \tcode{U} name the same type with the same cv-qualifications                            &   \\ \rowsep

\indexlibraryglobal{is_base_of}%
\tcode{template<class Base, class Derived>}\br
 \tcode{struct is_base_of;}                 &
 \tcode{Base} is a base class of \tcode{Derived}\iref{class.derived}
 without regard to cv-qualifiers
 or \tcode{Base} and \tcode{Derived} are not unions and
 name the same class type
 without regard to cv-qualifiers            &
 If \tcode{Base} and
 \tcode{Derived} are non-union class types and are
 not (possibly cv-qualified versions of) the same type,
 \tcode{Derived} shall be a complete
 type.
 \begin{tailnote}
 Base classes that are private, protected, or ambiguous
 are, nonetheless, base classes.
\end{tailnote}
\\ \rowsep

\indexlibraryglobal{is_virtual_base_of}%
\tcode{template<class Base, class Derived>}\br
 \tcode{struct is_virtual_base_of;}                 &
 \tcode{Base} is a virtual base class of \tcode{Derived}\iref{class.mi}
 without regard to cv-qualifiers.            &
 If \tcode{Base} and
 \tcode{Derived} are non-union class types,
 \tcode{Derived} shall be a complete type.
 \begin{note}
 Virtual base classes that are private, protected, or ambiguous
 are, nonetheless, virtual base classes.
 \end{note}
 \begin{tailnote}
 A class is never a virtual base class of itself.
 \end{tailnote}                                     \\ \rowsep

\indexlibraryglobal{is_convertible}%
\tcode{template<class From, class To>}\br
 \tcode{struct is_convertible;}             &
 \seebelow                                  &
 \tcode{From} and \tcode{To} shall be complete types,
 \cv{}~\keyword{void}, or arrays of unknown bound.  \\ \rowsep

\indexlibraryglobal{is_nothrow_convertible}%
\tcode{template<class From, class To>}\br
 \tcode{struct is_nothrow_convertible;}     &
 \tcode{is_convertible_v<From, To>} is \tcode{true} and
 the conversion, as defined by \tcode{is_convertible},
 is known not to throw any exceptions\iref{expr.unary.noexcept} &
 \tcode{From} and \tcode{To} shall be complete types,
 \cv{}~\keyword{void}, or arrays of unknown bound.  \\ \rowsep

\indexlibraryglobal{is_layout_compatible}%
\tcode{template<class T, class U>}\br
 \tcode{struct is_layout_compatible;}                 &
 \tcode{T} and \tcode{U} are layout-compatible\iref{term.layout.compatible.type}    &
 \tcode{T} and \tcode{U} shall be complete types,
 \cv{}~\keyword{void},
 or arrays of unknown bound.                \\ \rowsep

\indexlibraryglobal{is_pointer_interconvertible_base_of}%
\tcode{template<class Base, class Derived>}\br
 \tcode{struct is_pointer_interconvertible_base_of;}                 &
 \tcode{Derived} is unambiguously derived from \tcode{Base}
 without regard to cv-qualifiers,
 and each object of type \tcode{Derived}
 is pointer-interconvertible\iref{basic.compound} with
 its \tcode{Base} subobject,
 or \tcode{Base} and \tcode{Derived} are not unions
 and name the same class type
 without regard to cv-qualifiers.   &
 If \tcode{Base} and \tcode{Derived} are non-union class types
 and are not (possibly cv-qualified versions of) the same type,
 \tcode{Derived} shall be a complete type.  \\ \rowsep

\indexlibraryglobal{is_invocable}%
\tcode{template<class Fn, class... ArgTypes>}\br
 \tcode{struct is_invocable;}                      &
 The expression \tcode{\placeholdernc{INVOKE}(declval<Fn>(), declval<ArgTypes>()...)}\iref{func.require}
 is well-formed when treated as an unevaluated operand\iref{term.unevaluated.operand} &
 \tcode{Fn} and all types in the template parameter pack \tcode{ArgTypes}
 shall be complete types, \cv{}~\keyword{void}, or
 arrays of unknown bound.                                             \\ \rowsep

\indexlibraryglobal{is_invocable_r}%
\tcode{template<class R, class Fn, class... ArgTypes>}\br
 \tcode{struct is_invocable_r;}                      &
 The expression \tcode{\placeholdernc{INVOKE}<R>(declval<Fn>(), declval<ArgTypes>()...)}
 is well-formed when treated as an unevaluated operand                &
 \tcode{Fn}, \tcode{R}, and all types in the template parameter pack \tcode{ArgTypes}
 shall be complete types, \cv{}~\keyword{void}, or
 arrays of unknown bound.                                             \\ \rowsep

\indexlibraryglobal{is_nothrow_invocable}%
\tcode{template<class Fn, class... ArgTypes>}\br
 \tcode{struct is_nothrow_invocable;}              &
 \tcode{is_invocable_v<}\br\tcode{Fn, ArgTypes...>} is \tcode{true} and
 the expression \tcode{\placeholdernc{INVOKE}(declval<Fn>(), declval<ArgTypes>()...)}
 is known not to throw any exceptions\iref{expr.unary.noexcept}       &
 \tcode{Fn} and all types in the template parameter pack \tcode{ArgTypes}
 shall be complete types, \cv{}~\keyword{void}, or
 arrays of unknown bound.                                             \\ \rowsep

\indexlibraryglobal{is_nothrow_invocable_r}%
\tcode{template<class R, class Fn, class... ArgTypes>}\br
 \tcode{struct is_nothrow_invocable_r;}              &
 \tcode{is_invocable_r_v<}\br\tcode{R, Fn, ArgTypes...>} is \tcode{true} and
 the expression \tcode{\placeholdernc{INVOKE}<R>(declval<Fn>(), declval<ArgTypes>()...)}
 is known not to throw any exceptions\iref{expr.unary.noexcept}       &
 \tcode{Fn}, \tcode{R}, and all types in the template parameter pack \tcode{ArgTypes}
 shall be complete types, \cv{}~\keyword{void}, or
 arrays of unknown bound.                                             \\ \rowsep

\indexlibraryglobal{is_applicable}%
\tcode{template<class Fn, class Tuple>}\br
 \tcode{struct is_applicable;}              &
 \tcode{\exposconcept{tuple-like}<Tuple>} is \tcode{true} and
 the expression
 \tcode{\placeholdernc{INVOKE}(declval<Fn>(), \placeholdernc{ELEMS-OF}(Tuple)...)}
 is well-formed when treated as an unevaluated operand.       &
 \tcode{Fn} and \tcode{Tuple}
 shall be complete types, \cv{}~\keyword{void}, or
 arrays of unknown bound.                                             \\ \rowsep

\indexlibraryglobal{is_nothrow_applicable}%
\tcode{template<class Fn, class Tuple>}\br
 \tcode{struct is_nothrow_applicable;}              &
 \tcode{is_applicable_v<}\br\tcode{Fn, Tuple>} is \tcode{true} and
 the expression \tcode{\placeholdernc{INVOKE}(declval<Fn>(), \placeholdernc{ELEMS-OF}(Tuple)...)}
 is known not to throw any exceptions\iref{expr.unary.noexcept}.       &
 \tcode{Fn} and \tcode{Tuple}
 shall be complete types, \cv{}~\keyword{void}, or
 arrays of unknown bound.                                             \\
\end{libreqtab3f}

\pnum
For the purpose of defining the templates in this subclause,
a function call expression \tcode{declval<T>()} for any type \tcode{T}
is considered to be a trivial\iref{term.trivial.type,special} function call
that is not an odr-use\iref{term.odr.use} of \tcode{declval}
in the context of the corresponding definition
notwithstanding the restrictions of~\ref{declval}.

\pnum
\begin{example}
\begin{codeblock}
struct B {};
struct B1 : B {};
struct B2 : B {};
struct D : private B1, private B2 {};

is_base_of_v<B, D>              // \tcode{true}
is_base_of_v<const B, D>        // \tcode{true}
is_base_of_v<B, const D>        // \tcode{true}
is_base_of_v<B, const B>        // \tcode{true}
is_base_of_v<D, B>              // \tcode{false}
is_base_of_v<B&, D&>            // \tcode{false}
is_base_of_v<B[3], D[3]>        // \tcode{false}
is_base_of_v<int, int>          // \tcode{false}
\end{codeblock}
\end{example}

\indexlibraryglobal{is_convertible}%
\pnum
The predicate condition for a template specialization \tcode{is_convertible<From, To>}
shall be satisfied if and only if
the return statement\iref{stmt.return} in the following code would be
well-formed, including any implicit conversions to the return type of the function:

\begin{codeblock}
To test() {
  return declval<From>();
}
\end{codeblock}

\begin{note}
This requirement gives well-defined results for reference types,
array types, function types, and \cv{}~\keyword{void}.
\end{note}
Access checking is performed
in a context unrelated to \tcode{To} and \tcode{From}.
The operand of the \tcode{return} statement
(including initialization of the returned object or reference, if any)
is treated as an unevaluated operand\iref{expr.context}, and
only the validity of its immediate context is considered.
\begin{note}
The
initialization can result in side effects such as the
instantiation of class template specializations and function template
specializations, the generation of implicitly-defined functions, and so on. Such
side effects are not in the ``immediate context'' and can result in the program
being ill-formed.
\end{note}

\rSec2[meta.trans]{Transformations between types}

\rSec3[meta.trans.general]{General}
\pnum
Subclause \ref{meta.trans} contains templates that may be used to transform one
type to another following some predefined rule.

\pnum
Each of the templates in \ref{meta.trans} shall be a
\oldconcept{TransformationTrait}\iref{meta.rqmts}.

\rSec3[meta.trans.cv]{Const-volatile modifications}

\pnum
The templates specified in \tref{meta.trans.cv}
add or remove cv-qualifications\iref{basic.type.qualifier}.

\begin{libreqtab2a}{Const-volatile modifications}{meta.trans.cv}
\\ \topline
\lhdr{Template} &   \rhdr{Comments} \\ \capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template} &   \rhdr{Comments} \\ \capsep
\endhead

\indexlibraryglobal{remove_const}%
\tcode{template<class T>\br
 struct remove_const;}                  &
 The member typedef \tcode{type} denotes the type formed
 by removing any top-level const-qualifier from \tcode{T}.
 \begin{tailexample}
\tcode{remove_const_t<const volatile int>} evaluates
 to \tcode{volatile int}, whereas \tcode{remove_const_t<const int*>} evaluates to
 \tcode{const int*}.
\end{tailexample}
\\  \rowsep

\indexlibraryglobal{remove_volatile}%
\tcode{template<class T>\br
 struct remove_volatile;}               &
 The member typedef \tcode{type} denotes the type formed
 by removing any top-level volatile-qualifier from \tcode{T}.
 \begin{tailexample}
\tcode{remove_volatile_t<const volatile int>}
 evaluates to \tcode{const int},
 whereas \tcode{remove_volatile_t<volatile int*>} evaluates to \tcode{volatile int*}.
 \end{tailexample}
\\  \rowsep

\indexlibraryglobal{remove_cv}%
\tcode{template<class T>\br
 struct remove_cv;}                 &
 The member typedef \tcode{type} denotes the type formed
 by removing any top-level cv-qualifiers from \tcode{T}.
 \begin{tailexample}
\tcode{remove_cv_t<const volatile int>}
 evaluates to \tcode{int}, whereas \tcode{remove_cv_t<const volatile int*>}
 evaluates to \tcode{const volatile int*}.
\end{tailexample}
\\  \rowsep

\indexlibraryglobal{add_const}%
\tcode{template<class T>\br
 struct add_const;}                 &
 The member typedef \tcode{type} denotes \tcode{const T}.
\begin{tailnote}
\keyword{const} has no effect when \tcode{T} is a reference, function, or
top-level const-qualified type.
\end{tailnote}
\\ \rowsep

\indexlibraryglobal{add_volatile}%
\tcode{template<class T>\br
 struct add_volatile;}                  &
 The member typedef \tcode{type} denotes \tcode{volatile T}.
\begin{tailnote}
\keyword{volatile} has no effect when \tcode{T} is a reference, function, or
top-level volatile-qualified type.
\end{tailnote}
\\ \rowsep

\indexlibraryglobal{add_cv}%
\tcode{template<class T>\br
 struct add_cv;}                    &
 The member typedef \tcode{type} denotes
 \tcode{add_const_t<add_volatile_t<T>>}.                               \\
\end{libreqtab2a}

\rSec3[meta.trans.ref]{Reference modifications}

\pnum
The templates specified in \tref{meta.trans.ref}
add or remove references.

\begin{libreqtab2a}{Reference modifications}{meta.trans.ref}
\\ \topline
\lhdr{Template} &   \rhdr{Comments} \\ \capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template} &   \rhdr{Comments} \\ \capsep
\endhead

\indexlibraryglobal{remove_reference}%
\tcode{template<class T>\br
 struct remove_reference;}                  &
 If \tcode{T} has type ``reference to \tcode{T1}'' then the
 member typedef \tcode{type} denotes \tcode{T1};
 otherwise, \tcode{type} denotes \tcode{T}.\\ \rowsep

\indexlibraryglobal{add_lvalue_reference}%
\tcode{template<class T>\br
 struct add_lvalue_reference;}                     &
 If \tcode{T} is a referenceable type\iref{defns.referenceable} then
 the member typedef \tcode{type} denotes \tcode{T\&};
 otherwise, \tcode{type} denotes \tcode{T}.
 \begin{tailnote}
 This rule reflects the semantics of reference collapsing\iref{dcl.ref}.
 \end{tailnote}
\\ \rowsep

\indexlibraryglobal{add_rvalue_reference}%
\tcode{template<class T>}\br
 \tcode{struct add_rvalue_reference;}    &
 If \tcode{T} is a referenceable type then
 the member typedef \tcode{type} denotes \tcode{T\&\&};
 otherwise, \tcode{type} denotes \tcode{T}.
 \begin{tailnote}
This rule reflects the semantics of reference collapsing\iref{dcl.ref}.
 For example, when a type \tcode{T} is a reference type \tcode{T1\&},
 the type \tcode{add_rvalue_reference_t<T>} is not an rvalue reference.
 \end{tailnote}
\\
\end{libreqtab2a}

\rSec3[meta.trans.sign]{Sign modifications}

\pnum
The templates specified in \tref{meta.trans.sign}
convert an integer type to its corresponding signed or unsigned type.

\begin{libreqtab2a}{Sign modifications}{meta.trans.sign}
\\ \topline
\lhdr{Template} &   \rhdr{Comments} \\ \capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template} &   \rhdr{Comments} \\ \capsep
\endhead

\indexlibraryglobal{make_signed}%
\tcode{template<class T>}\br
 \tcode{struct make_signed;} &
 If \tcode{T} is a (possibly cv-qualified) signed integer
 type\iref{basic.fundamental} then the member typedef
 \tcode{type} denotes \tcode{T}; otherwise,
 if \tcode{T} is a (possibly cv-qualified) unsigned integer
 type then \tcode{type} denotes the corresponding
 signed integer type, with the same cv-qualifiers as \tcode{T};
 otherwise, \tcode{type} denotes the signed integer type with smallest
 rank\iref{conv.rank} for which
 \tcode{sizeof(T) == sizeof(type)}, with the same
 cv-qualifiers as \tcode{T}.\br
 \mandates \tcode{T} is an integral or enumeration type
 other than \cv~\tcode{bool}.\\ \rowsep

\indexlibraryglobal{make_unsigned}%
\tcode{template<class T>}\br
 \tcode{struct make_unsigned;} &
 If \tcode{T} is a (possibly cv-qualified) unsigned integer
 type\iref{basic.fundamental} then the member typedef
 \tcode{type} denotes \tcode{T}; otherwise,
 if \tcode{T} is a (possibly cv-qualified) signed integer
 type then \tcode{type} denotes the corresponding
 unsigned integer type, with the same cv-qualifiers as \tcode{T};
 otherwise, \tcode{type} denotes the unsigned integer type with smallest
 rank\iref{conv.rank} for which
 \tcode{sizeof(T) == sizeof(type)}, with the same
 cv-qualifiers as \tcode{T}.\br
 \mandates \tcode{T} is an integral or enumeration type
 other than \cv~\tcode{bool}.\\
\end{libreqtab2a}

\rSec3[meta.trans.arr]{Array modifications}

\pnum
The templates specified in \tref{meta.trans.arr}
modify array types.

\begin{libreqtab2a}{Array modifications}{meta.trans.arr}
\\ \topline
\lhdr{Template} &   \rhdr{Comments} \\ \capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template} &   \rhdr{Comments} \\ \capsep
\endhead

\indexlibraryglobal{remove_extent}%
\tcode{template<class T>\br
 struct remove_extent;}                 &
 If \tcode{T} is a type ``array of \tcode{U}'',
 the member typedef \tcode{type} denotes \tcode{U},
 otherwise \tcode{T}.
 \begin{tailnote}
For multidimensional arrays, only the first array dimension is
 removed. For a type ``array of \tcode{const U}'', the resulting type is
 \tcode{const U}.
\end{tailnote}
\\  \rowsep

\indexlibraryglobal{remove_all_extents}%
\tcode{template<class T>\br
 struct remove_all_extents;}                &
 If \tcode{T} is ``multidimensional array of \tcode{U}'', the resulting member
 typedef \tcode{type} denotes \tcode{U}, otherwise \tcode{T}.                                       \\
\end{libreqtab2a}

\pnum
\begin{example}
\begin{codeblock}
// the following assertions hold:
static_assert(is_same_v<remove_extent_t<int>, int>);
static_assert(is_same_v<remove_extent_t<int[2]>, int>);
static_assert(is_same_v<remove_extent_t<int[2][3]>, int[3]>);
static_assert(is_same_v<remove_extent_t<int[][3]>, int[3]>);
\end{codeblock}
\end{example}

\pnum
\begin{example}
\begin{codeblock}
// the following assertions hold:
static_assert(is_same_v<remove_all_extents_t<int>, int>);
static_assert(is_same_v<remove_all_extents_t<int[2]>, int>);
static_assert(is_same_v<remove_all_extents_t<int[2][3]>, int>);
static_assert(is_same_v<remove_all_extents_t<int[][3]>, int>);
\end{codeblock}
\end{example}

\rSec3[meta.trans.ptr]{Pointer modifications}

\pnum
The templates specified in \tref{meta.trans.ptr}
add or remove pointers.

\begin{libreqtab2a}{Pointer modifications}{meta.trans.ptr}
\\ \topline
\lhdr{Template} &   \rhdr{Comments} \\ \capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template} &   \rhdr{Comments} \\ \capsep
\endhead

\indexlibraryglobal{remove_pointer}%
\tcode{template<class T>\br
 struct remove_pointer;}                    &
 If \tcode{T} has type ``(possibly cv-qualified) pointer
 to \tcode{T1}'' then the member typedef \tcode{type}
 denotes \tcode{T1}; otherwise, it denotes \tcode{T}.\\ \rowsep

\indexlibraryglobal{add_pointer}%
\tcode{template<class T>\br
 struct add_pointer;}                       &
 If \tcode{T} is a referenceable type\iref{defns.referenceable} or a
 \cv{}~\keyword{void} type then
 the member typedef \tcode{type} denotes
 \tcode{remove_reference_t<T>*};
 otherwise, \tcode{type} denotes \tcode{T}.             \\
\end{libreqtab2a}

\rSec3[meta.trans.other]{Other transformations}

\pnum
The templates specified in \tref{meta.trans.other}
perform other modifications of a type.

\begin{libreqtab2a}{Other transformations}{meta.trans.other}
\\ \topline
\lhdr{Template}   &   \rhdr{Comments} \\ \capsep
\endfirsthead
\continuedcaption\\
\topline
\lhdr{Template}   &   \rhdr{Comments} \\ \capsep
\endhead

\tcode{template<class T>\br
 struct \libglobal{type_identity};}
 &
 The member typedef \tcode{type} denotes \tcode{T}. \\ \rowsep

\tcode{template<class T>\br struct \libglobal{remove_cvref};}
 &
 The member typedef \tcode{type} denotes
 \tcode{remove_cv_t<remove_reference_t<T>>}.
 \\ \rowsep

\tcode{template<class T>\br struct \libglobal{decay};}
 &
 Let \tcode{U} be \tcode{remove_reference_t<T>}. If \tcode{is_array_v<U>} is
 \tcode{true}, the member typedef \tcode{type} denotes
 \tcode{remove_extent_t<U>*}. If \tcode{is_function_v<U>} is \tcode{true},
 the member typedef \tcode{type} denotes \tcode{add_pointer_t<U>}. Otherwise
 the member typedef \tcode{type} denotes \tcode{remove_cv_t<U>}.
\begin{tailnote}
This behavior is similar to the lvalue-to-rvalue\iref{conv.lval},
array-to-pointer\iref{conv.array}, and function-to-pointer\iref{conv.func}
conversions applied when an lvalue is used as an rvalue, but also
strips cv-qualifiers from class types in order to more closely model by-value
argument passing.
\end{tailnote}
 \\ \rowsep

\tcode{template<bool B, class T = void>} \tcode{struct \libglobal{enable_if};}
 &
 If \tcode{B} is \tcode{true}, the member typedef \tcode{type}
 denotes \tcode{T}; otherwise, there shall be no member
 \tcode{type}. \\ \rowsep

\tcode{template<bool B, class T,}
 \tcode{class F>}\br
 \tcode{struct \libglobal{conditional};}
 &
 If \tcode{B} is \tcode{true},  the member typedef \tcode{type} denotes \tcode{T}.
 If \tcode{B} is \tcode{false}, the member typedef \tcode{type} denotes \tcode{F}. \\ \rowsep

 \tcode{template<class... T>} \tcode{struct common_type;}
 &
 Unless this trait is specialized,
 the member \tcode{type} is declared or omitted as specified below.
 If it is omitted, there shall be no member \tcode{type}.
 Each type in the template parameter pack \tcode{T} shall be
 complete, \cv{}~\keyword{void}, or an array of unknown bound. \\ \rowsep

\tcode{template<class, class,}
 \hspace*{2ex}\tcode{template<class> class,}
 \hspace*{2ex}\tcode{template<class> class>}
 \keyword{struct}
 \hspace*{2ex}\tcode{\libglobal{basic_common_reference};}
 &
 Unless this trait is specialized,
 there shall be no member \tcode{type}. \\ \rowsep

\tcode{template<class... T>} \tcode{struct \libglobal{common_reference};}
 &
 The member \grammarterm{typedef-name} \tcode{type} is declared or omitted
 as specified below. Each type in the parameter pack \tcode{T} shall
 be complete or \cv{} \keyword{void}. \\ \rowsep

\tcode{template<class T>}\br
 \tcode{struct \libglobal{underlying_type};}
 &
 If \tcode{T} is an enumeration type, the member typedef \tcode{type} denotes
 the underlying type of \tcode{T}\iref{dcl.enum};
 otherwise, there is no member \tcode{type}.\br
 \mandates \tcode{T} is not an incomplete enumeration type. \\ \rowsep

\tcode{template<class Fn,}\br
 \tcode{class... ArgTypes>}\br
 \tcode{struct \libglobal{invoke_result};}
 &
 If the expression \tcode{\placeholdernc{INVOKE}(declval<Fn>(), declval<ArgTypes>()...)}\iref{func.require}
 is well-formed when treated as an unevaluated operand\iref{term.unevaluated.operand},
 the member typedef \tcode{type} denotes the type
 \tcode{decltype(\placeholdernc{INVOKE}(declval<Fn>(), declval<ArgTypes>()...))};
 otherwise, there shall be no member \tcode{type}. Access checking is
 performed as if in a context unrelated to \tcode{Fn} and
 \tcode{ArgTypes}. Only the validity of the immediate context of the
 expression is considered.
 \begin{note}
 The compilation of the expression can result in side effects such as
 the instantiation of class template specializations and function
 template specializations, the generation of implicitly-defined
 functions, and so on. Such side effects are not in the ``immediate
 context'' and can result in the program being ill-formed.
 \end{note}
 \expects \tcode{Fn} and all types in the template parameter pack \tcode{ArgTypes}
 are complete types, \cv{}~\keyword{void}, or arrays of
 unknown bound.\\ \rowsep

\tcode{template<class Fn, class Tuple>}\br
 \tcode{struct \libglobal{apply_result};}
 &
 If \tcode{\exposconcept{tuple-like}<Tuple>} is \tcode{true}
 and the expression
 \tcode{\placeholdernc{INVOKE}(declval<Fn>(), \placeholdernc{ELEMS-OF}(Tuple)...)}\iref{func.require}
 is well-formed
 when treated as an unevaluated operand\iref{term.unevaluated.operand},
 the member typedef \tcode{type} denotes the type
 \tcode{decltype(\placeholdernc{INVOKE}(declval<Fn>(), \placeholdernc{ELEMS-OF}(Tuple)...))};
 otherwise, there shall be no member \tcode{type}.
 Access checking is performed as if in a context unrelated to \tcode{Fn}
 and \tcode{Tuple}.
 Only the validity of the immediate context of the expression is considered.
 \begin{note}
 The compilation of the expression can result in side effects
 such as the instantiation of class template specializations
 and function template specializations,
 the generation of implicitly-defined functions, and so on.
 Such side effects are not in the ``immediate context''
 and can result in the program being ill-formed.
 \end{note}
 \expects
 \tcode{Fn} and \tcode{Tuple} are complete types, \cv{}~\keyword{void},
 or arrays of unknown bound.\\ \rowsep

\tcode{template<class T>} \tcode{struct \libglobal{unwrap_reference};}
 &
 If \tcode{T} is
 a specialization \tcode{reference_wrapper<X>} for some type \tcode{X},
 the member typedef \tcode{type} of \tcode{unwrap_reference<T>}
 denotes \tcode{X\&},
 otherwise \tcode{type} denotes \tcode{T}. \\ \rowsep

\tcode{template<class T>} \tcode{\libglobal{unwrap_ref_decay};}
 &
 The member typedef \tcode{type} of \tcode{unwrap_ref_decay<T>}
 denotes the type \tcode{unwrap_reference_t<decay_t<T>>}.\\
\end{libreqtab2a}

\pnum
In addition to being available via inclusion
of the \tcode{<type_traits>} header, the templates
\tcode{unwrap_reference},
\tcode{unwrap_ref_decay},
\tcode{unwrap_reference_t}, and
\tcode{unwrap_ref_decay_t}
are available
when the header \tcode{<func\-tional>}\iref{functional.syn} is included.

\indexlibraryglobal{common_type}%
\pnum
Let:
\begin{itemize}
\item \tcode{\placeholdernc{CREF}(A)} be
  \tcode{add_lvalue_reference_t<const remove_reference_t<A>{}>},
\item \tcode{\placeholdernc{XREF}(A)} denote a unary alias template \tcode{T}
  such that \tcode{T<U>} denotes the same type as \tcode{U} with the addition
  of \tcode{A}'s cv and reference qualifiers, for a non-reference cv-unqualified
  type \tcode{U},
\item \tcode{\placeholdernc{COPYCV}(FROM, TO)} be an alias for type \tcode{TO}
  with the addition of \tcode{FROM}'s top-level cv-qualifiers,
  \begin{example}
    \tcode{\placeholdernc{COPYCV}(const int, volatile short)} is an alias for
    \tcode{const volatile short}.
  \end{example}
\item \tcode{\placeholdernc{COND-RES}(X, Y)} be
  \tcode{decltype(false ?\ declval<X(\&)()>()() :\ declval<Y(\&)()>()())}.
\end{itemize}
Given types \tcode{A} and \tcode{B},
let \tcode{X} be \tcode{remove_reference_t<A>},
let \tcode{Y} be \tcode{remove_reference_t<B>}, and
let \tcode{\placeholdernc{COMMON-\brk{}REF}(A, B)} be:
\begin{itemize}
\item If \tcode{A} and \tcode{B} are both lvalue reference types,
  \tcode{\placeholdernc{COMMON-REF}(A, B)} is
  \tcode{\placeholdernc{COND-RES}(\placeholdernc{COPYCV}(X, Y) \&,
    \placeholdernc{COPYCV}(\brk{}Y, X) \&)} if that type exists
  and is a reference type.
\item Otherwise, let \tcode{C} be
  \tcode{remove_reference_t<\placeholdernc{COMMON-REF}(X\&, Y\&)>\&\&}.
  If \tcode{A} and \tcode{B} are both rvalue reference types,
  \tcode{C} is well-formed, and
  \tcode{is_convertible_v<A, C> \&\& is_convertible_v<B, C>} is \tcode{true},
  then \tcode{\placeholdernc{COMMON-REF}(A, B)} is \tcode{C}.
\item Otherwise, let \tcode{D} be
  \tcode{\placeholdernc{COMMON-REF}(const X\&, Y\&)}. If \tcode{A} is an rvalue
  reference and \tcode{B} is an lvalue reference and \tcode{D} is
  well-formed and \tcode{is_convertible_v<A, D>} is
  \tcode{true}, then \tcode{\placeholdernc{COMMON-REF}(A, B)} is \tcode{D}.
\item Otherwise, if \tcode{A} is an lvalue reference and \tcode{B}
  is an rvalue reference, then \tcode{\placeholdernc{COMMON-REF}(A, B)} is
  \tcode{\placeholdernc{COMMON-REF}(B, A)}.
\item Otherwise, \tcode{\placeholdernc{COMMON-REF}(A, B)} is ill-formed.
\end{itemize}

If any of the types computed above is ill-formed, then
\tcode{\placeholdernc{COMMON-REF}(A, B)} is ill-formed.

\pnum
For the \tcode{common_type} trait applied to a template parameter pack \tcode{T} of types,
the member \tcode{type} shall be either declared or not present as follows:

\begin{itemize}
\item If \tcode{sizeof...(T)} is zero, there shall be no member \tcode{type}.

\item If \tcode{sizeof...(T)} is one, let \tcode{T0} denote the sole type
constituting the pack \tcode{T}.
The member \grammarterm{typedef-name} \tcode{type} shall denote the same
type, if any, as \tcode{common_type_t<T0, T0>};
otherwise there shall be no member \tcode{type}.

\item If \tcode{sizeof...(T)} is two,
let the first and second types constituting \tcode{T} be denoted
by \tcode{T1} and \tcode{T2}, respectively, and
let \tcode{D1} and \tcode{D2} denote
the same types as \tcode{decay_t<T1>} and \tcode{decay_t<T2>}, respectively.
  \begin{itemize}
  \item If \tcode{is_same_v<T1, D1>} is \tcode{false} or
     \tcode{is_same_v<T2, D2>} is \tcode{false},
     let \tcode{C} denote the same type, if any,
     as \tcode{common_type_t<D1, D2>}.
  \item
    \begin{note}
      None of the following will apply if there is a specialization
      \tcode{common_type<D1, D2>}.
    \end{note}
  \item Otherwise, if
\begin{codeblock}
decay_t<decltype(false ? declval<D1>() : declval<D2>())>
\end{codeblock}
    denotes a valid type, let \tcode{C} denote that type.
  \item Otherwise, if
    \tcode{\placeholdernc{COND-RES}(\placeholdernc{CREF}(D1),
      \placeholdernc{CREF}(D2))}
    denotes a type, let \tcode{C} denote the type
    \tcode{decay_t<\placeholdernc{COND-RES}(\placeholdernc{CREF}(D1),
      \placeholdernc{CREF}(D2))>}.
  \end{itemize}
In either case, the member \grammarterm{typedef-name} \tcode{type} shall denote
the same type, if any, as \tcode{C}.
Otherwise, there shall be no member \tcode{type}.

\item If \tcode{sizeof...(T)} is greater than two,
let \tcode{T1}, \tcode{T2}, and \tcode{R}, respectively,
denote the first, second, and (pack of) remaining types constituting \tcode{T}.
Let \tcode{C} denote the same type, if any, as \tcode{common_type_t<T1, T2>}.
If there is such a type \tcode{C}, the member \grammarterm{typedef-name} \tcode{type}
shall denote the same type, if any, as \tcode{common_type_t<C, R...>}.
Otherwise, there shall be no member \tcode{type}.
\end{itemize}

\pnum
Notwithstanding the provisions of \ref{meta.rqmts}, and
pursuant to \ref{namespace.std},
a program may specialize \tcode{common_type<T1, T2>}
for types \tcode{T1} and \tcode{T2} such that
\tcode{is_same_v<T1, decay_t<T1>>} and
\tcode{is_same_v<T2, decay_t<T2>>} are each \tcode{true}.
\begin{note}
Such specializations are needed when only explicit conversions
are desired between the template arguments.
\end{note}
Such a specialization need not have a member named \tcode{type},
but if it does,
the \grammarterm{qualified-id} \tcode{common_type<T1, T2>::type} shall denote
a cv-unqualified non-reference type
to which each of the types \tcode{T1} and \tcode{T2} is explicitly convertible.
Moreover, \tcode{common_type_t<T1, T2>} shall denote
the same type, if any, as does \tcode{common_type_t<T2, T1>}.
No diagnostic is required for a violation of this Note's rules.

\pnum
For the \tcode{common_reference} trait applied to a parameter pack
\tcode{T} of types, the member \tcode{type} shall be either declared or not
present as follows:
\begin{itemize}
\item If \tcode{sizeof...(T)} is zero, there shall be no member \tcode{type}.

\item Otherwise, if \tcode{sizeof...(T)} is one, let \tcode{T0} denote the sole
  type in the pack \tcode{T}. The member typedef \tcode{type} shall denote the
  same type as \tcode{T0}.

\item Otherwise, if \tcode{sizeof...(T)} is two, let \tcode{T1} and \tcode{T2}
  denote the two types in the pack \tcode{T}. Then
  \begin{itemize}
  \item Let \tcode{R} be \tcode{\placeholdernc{COMMON-REF}(T1, T2)}.
    If \tcode{T1} and \tcode{T2} are reference types,
    \tcode{R} is well-formed, and
    \tcode{is_convertible_v<add_pointer_t<T1>, add_pointer_t<R>> \&\& is_convertible_v<add_poin\linebreak{}ter_t<T2>, add_pointer_t<R>>} is \tcode{true},
    then the member typedef \tcode{type} denotes \tcode{R}.

  \item Otherwise, if
    \tcode{basic_common_reference<remove_cvref_t<T1>, remove_cvref_t<T2>,
      \brk{}\placeholdernc{XREF}(\brk{}T1), \placeholdernc{XREF}(T2)>::type}
    is well-formed, then the member typedef \tcode{type} denotes that type.

  \item Otherwise, if \tcode{\placeholdernc{COND-RES}(T1, T2)} is well-formed,
    then the member typedef \tcode{type} denotes that type.

  \item Otherwise, if \tcode{common_type_t<T1, T2>} is well-formed, then the
    member typedef \tcode{type} denotes that type.

  \item Otherwise, there shall be no member \tcode{type}.
  \end{itemize}

\item Otherwise, if \tcode{sizeof...(T)} is greater than two, let \tcode{T1},
  \tcode{T2}, and \tcode{Rest}, respectively, denote the first, second, and
  (pack of) remaining types comprising \tcode{T}. Let \tcode{C} be the type
  \tcode{common_reference_t<T1, T2>}. Then:
  \begin{itemize}
  \item If there is such a type \tcode{C}, the member typedef \tcode{type} shall
    denote the same type, if any, as \tcode{common_reference_t<C, Rest...>}.

  \item Otherwise, there shall be no member \tcode{type}.
  \end{itemize}
\end{itemize}

\pnum
Notwithstanding the provisions of \ref{meta.rqmts}, and
pursuant to \ref{namespace.std}, a program may partially specialize
\tcode{basic_common_reference<T, U, TQual, UQual>}
for types \tcode{T} and \tcode{U} such that
\tcode{is_same_v<T, decay_t<T>>} and
\tcode{is_same_v<U, decay_t<U>>} are each \tcode{true}.
\begin{note}
Such specializations
can be used to influence the result of \tcode{common_reference}, and
are needed when only explicit conversions are desired
between the template arguments.
\end{note}
Such a specialization need not have a member named \tcode{type}, but if it does,
the \grammarterm{qualified-id}
\tcode{basic_common_reference<T, U, TQual, UQual>::type}
shall denote a type
to which each of the types \tcode{TQual<T>} and
\tcode{UQual<U>} is convertible.
Moreover, \tcode{basic_common_reference<T, U, TQual, UQual>::type} shall denote
the same type, if any, as does
\tcode{basic_common_reference<U, T, UQual, TQual>::type}.
No diagnostic is required for a violation of these rules.

\pnum
\begin{example}
Given these declarations:
\begin{codeblock}
using PF1 = bool  (&)();
using PF2 = short (*)(long);

struct S {
  operator PF2() const;
  double operator()(char, int&);
  void fn(long) const;
  char data;
};

using PMF = void (S::*)(long) const;
using PMD = char  S::*;
\end{codeblock}
the following assertions will hold:
\begin{codeblock}
static_assert(is_same_v<invoke_result_t<S, int>, short>);
static_assert(is_same_v<invoke_result_t<S&, unsigned char, int&>, double>);
static_assert(is_same_v<invoke_result_t<PF1>, bool>);
static_assert(is_same_v<invoke_result_t<PMF, unique_ptr<S>, int>, void>);
static_assert(is_same_v<invoke_result_t<PMD, S>, char&&>);
static_assert(is_same_v<invoke_result_t<PMD, const S*>, const char&>);
\end{codeblock}
\end{example}

\rSec2[meta.logical]{Logical operator traits}

\pnum
This subclause describes type traits for applying logical operators
to other type traits.

\indexlibraryglobal{conjunction}%
\begin{itemdecl}
template<class... B> struct conjunction : @\seebelow@ { };
\end{itemdecl}

\begin{itemdescr}
\pnum
The class template \tcode{conjunction}
forms the logical conjunction of its template type arguments.

\pnum
For a specialization \tcode{conjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>},
if there is a template type argument $\tcode{B}_{i}$
for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{false},
then instantiating \tcode{conjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>::value}
does not require the instantiation of \tcode{$\tcode{B}_{j}$::value} for $j > i$.
\begin{note}
This is analogous to the short-circuiting behavior of
the built-in operator \tcode{\&\&}.
\end{note}

\pnum
Every template type argument
for which \tcode{$\tcode{B}_{i}$::value} is instantiated
shall be usable as a base class and
shall have a member \tcode{value} which
is convertible to \tcode{bool},
is not hidden, and
is unambiguously available in the type.

\pnum
The specialization \tcode{conjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>}
has a public and unambiguous base that is either
\begin{itemize}
\item
the first type $\tcode{B}_{i}$ in the list \tcode{true_type, $\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$}
for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{false}, or
\item
if there is no such $\tcode{B}_{i}$, the last type in the list.
\end{itemize}
\begin{note}
This means a specialization of \tcode{conjunction}
does not necessarily inherit from
either \tcode{true_type} or \tcode{false_type}.
\end{note}

\pnum
The member names of the base class, other than \tcode{conjunction} and
\tcode{operator=}, shall not be hidden and shall be unambiguously available
in \tcode{conjunction}.
\end{itemdescr}

\indexlibraryglobal{disjunction}%
\begin{itemdecl}
template<class... B> struct disjunction : @\seebelow@ { };
\end{itemdecl}

\begin{itemdescr}
\pnum
The class template \tcode{disjunction}
forms the logical disjunction of its template type arguments.

\pnum
For a specialization \tcode{disjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>},
if there is a template type argument $\tcode{B}_{i}$
for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{true},
then instantiating \tcode{disjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>::value}
does not require the instantiation of \tcode{$\tcode{B}_{j}$::value} for $j > i$.
\begin{note}
This is analogous to the short-circuiting behavior of
the built-in operator \tcode{||}.
\end{note}

\pnum
Every template type argument
for which \tcode{$\tcode{B}_{i}$::value} is instantiated
shall be usable as a base class and
shall have a member \tcode{value} which
is convertible to \tcode{bool},
is not hidden, and
is unambiguously available in the type.

\pnum
The specialization \tcode{disjunction<$\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$>}
has a public and unambiguous base that is either
\begin{itemize}
\item the first type $\tcode{B}_{i}$ in the list \tcode{false_type, $\tcode{B}_{1}$, $\dotsc$, $\tcode{B}_{N}$}
for which \tcode{bool($\tcode{B}_{i}$::value)} is \tcode{true}, or
\item if there is no such $\tcode{B}_{i}$, the last type in the list.
\end{itemize}
\begin{note}
This means a specialization of \tcode{disjunction}
does not necessarily inherit from
either \tcode{true_type} or \tcode{false_type}.
\end{note}

\pnum
The member names of the base class,
other than \tcode{disjunction} and \tcode{operator=},
shall not be hidden and shall be unambiguously available in \tcode{disjunction}.
\end{itemdescr}

\indexlibraryglobal{negation}%
\begin{itemdecl}
template<class B> struct negation : @\seebelow@ { };
\end{itemdecl}

\begin{itemdescr}
\pnum
The class template \tcode{negation}
forms the logical negation of its template type argument.
The type \tcode{negation<B>}
is a \oldconcept{UnaryTypeTrait} with a base characteristic of \tcode{bool_constant<!bool(B::\brk{}value)>}.
\end{itemdescr}

\rSec2[meta.member]{Member relationships}

\indexlibraryglobal{is_pointer_interconvertible_with_class}
\begin{itemdecl}
template<class S, class M>
  constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
\tcode{S} is a complete type.

\pnum
\returns
\tcode{true} if and only if
 \tcode{S} is a standard-layout type,
 \tcode{M} is an object type,
 \tcode{m} is not null,
 and each object \tcode{s} of type \tcode{S}
 is pointer-interconvertible\iref{basic.compound}
 with its subobject \tcode{s.*m}.
\end{itemdescr}

\indexlibraryglobal{is_corresponding_member}
\begin{itemdecl}
template<class S1, class S2, class M1, class M2>
  constexpr bool is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
\tcode{S1} and \tcode{S2} are complete types.

\pnum
\returns
\tcode{true} if and only if
 \tcode{S1} and \tcode{S2} are standard-layout struct\iref{class.prop} types,
 \tcode{M1} and \tcode{M2} are object types,
 \tcode{m1} and \tcode{m2} are not null,
 and \tcode{m1} and \tcode{m2} point to corresponding members of
 the common initial sequence\iref{class.mem} of \tcode{S1} and \tcode{S2}.
\end{itemdescr}

\pnum
\begin{note}
The type of a pointer-to-member expression \tcode{\&C::b}
is not always a pointer to member of \tcode{C},
leading to potentially surprising results
when using these functions in conjunction with inheritance.
\begin{example}
\begin{codeblock}
struct A { int a; };                    // a standard-layout class
struct B { int b; };                    // a standard-layout class
struct C: public A, public B { };       // not a standard-layout class

static_assert( is_pointer_interconvertible_with_class( &C::b ) );
  // Succeeds because, despite its appearance, \tcode{\&C::b} has type
  // ``pointer to member of \tcode{B} of type \tcode{int}''.
static_assert( !is_pointer_interconvertible_with_class<C, int>( &C::b ) );
  // Forces the use of class \tcode{C}, and the result is \tcode{false}.

static_assert( is_corresponding_member( &C::a, &C::b ) );
  // Succeeds because, despite its appearance, \tcode{\&C::a} and \tcode{\&C::b} have types
  // ``pointer to member of \tcode{A} of type \tcode{int}'' and
  // ``pointer to member of \tcode{B} of type \tcode{int}'', respectively.
static_assert( !is_corresponding_member<C, C, int, int>( &C::a, &C::b ) );
  // Forces the use of class \tcode{C}, and the result is \tcode{false}.
\end{codeblock}
\end{example}
\end{note}

\rSec2[meta.const.eval]{Constant evaluation context}

\indexlibraryglobal{is_constant_evaluated}%
\begin{itemdecl}
constexpr bool is_constant_evaluated() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if consteval {
  return true;
} else {
  return false;
}
\end{codeblock}

\pnum
\begin{example}
\begin{codeblock}
constexpr void f(unsigned char *p, int n) {
  if (std::is_constant_evaluated()) {           // should not be a constexpr if statement
    for (int k = 0; k<n; ++k) p[k] = 0;
  } else {
    memset(p, 0, n);                            // not a core constant expression
  }
}
\end{codeblock}
\end{example}
\end{itemdescr}

\indexlibraryglobal{is_within_lifetime}%
\begin{itemdecl}
template<class U = void, class T>
  consteval bool is_within_lifetime(const T* p) noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
\tcode{static_cast<const volatile U*>(p)} is well-formed.

\pnum
\returns
\tcode{true} if \tcode{p} is a pointer to an object that is
within its lifetime\iref{basic.life} and
\tcode{static_cast<const volatile U*>(p)} is a constant subexpression;
otherwise, \tcode{false}.

\pnum
\remarks
During the evaluation of an expression \tcode{E} as a core constant expression,
a call to this function is ill-formed
unless \tcode{p} points to an object that is usable
in constant expressions or
whose complete object's lifetime began within \tcode{E}.

\pnum
\begin{example}
\begin{codeblock}
struct OptBool {
  union { bool b; char c; };

  // note: this assumes common implementation properties for \tcode{bool} and \tcode{char}:
  // * \tcode{sizeof(bool) == sizeof(char)}, and
  // * the value representations for \tcode{true} and \tcode{false} are distinct
  //   from the value representation for \tcode{2}
  constexpr OptBool() : c(2) { }
  constexpr OptBool(bool b) : b(b) { }

  constexpr auto has_value() const -> bool {
    if consteval {
      return std::is_within_lifetime(&b);       // during constant evaluation, cannot read from \tcode{c}
    } else {
      return c != 2;                            // during runtime, must read from \tcode{c}
    }
  }

  constexpr auto operator*() const -> const bool& {
    return b;
  }
};

constexpr OptBool disengaged;
constexpr OptBool engaged(true);
static_assert(!disengaged.has_value());
static_assert(engaged.has_value());
static_assert(*engaged);
\end{codeblock}
\end{example}
\end{itemdescr}

\rSec1[meta.reflection]{Reflection}

\rSec2[meta.syn]{Header \tcode{<meta>} synopsis}

\indexheader{meta}%
\begin{codeblock}
#include <compare>              // see \ref{compare.syn}
#include <initializer_list>     // see \ref{initializer.list.syn}

namespace std {
  // \ref{meta.string.literal}, checking string literals
  consteval bool is_string_literal(const char* p);
  consteval bool is_string_literal(const wchar_t* p);
  consteval bool is_string_literal(const char8_t* p);
  consteval bool is_string_literal(const char16_t* p);
  consteval bool is_string_literal(const char32_t* p);

  // \ref{meta.define.static}, promoting to static storage
  namespace meta {
    template<ranges::@\libconcept{input_range}@ R>
      consteval info reflect_constant_string(R&& r);
    template<ranges::@\libconcept{input_range}@ R>
      consteval info reflect_constant_array(R&& r);
  }
  template<ranges::@\libconcept{input_range}@ R>
    consteval const ranges::range_value_t<R>* define_static_string(R&& r);
  template<ranges::@\libconcept{input_range}@ R>
    consteval span<const ranges::range_value_t<R>, @\seebelow@> define_static_array(R&& r);
  template<class T>
    consteval const remove_cvref_t<T>* define_static_object(T&& r);
}

namespace std::meta {
  using info = decltype(^^::);

  // \ref{meta.reflection.exception}, class \tcode{exception}
  class exception;

  // \ref{meta.reflection.operators}, operator representations
  enum class operators {
    @\seebelow@;
  };
  using enum operators;
  consteval operators operator_of(info r);
  consteval string_view symbol_of(operators op);
  consteval u8string_view u8symbol_of(operators op);

  // \ref{meta.reflection.names}, reflection names and locations
  consteval bool has_identifier(info r);

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

  consteval string_view display_string_of(info r);
  consteval u8string_view u8display_string_of(info r);

  consteval source_location source_location_of(info r);

  // \ref{meta.reflection.queries}, reflection queries
  consteval info type_of(info r);
  consteval info object_of(info r);
  consteval info constant_of(info r);

  consteval bool is_public(info r);
  consteval bool is_protected(info r);
  consteval bool is_private(info r);

  consteval bool is_virtual(info r);
  consteval bool is_pure_virtual(info r);
  consteval bool is_override(info r);
  consteval bool is_final(info r);

  consteval bool is_deleted(info r);
  consteval bool is_defaulted(info r);
  consteval bool is_user_provided(info r);
  consteval bool is_user_declared(info r);
  consteval bool is_explicit(info r);
  consteval bool is_noexcept(info r);

  consteval bool is_bit_field(info r);
  consteval bool is_enumerator(info r);
  consteval bool is_annotation(info r);

  consteval bool is_const(info r);
  consteval bool is_volatile(info r);
  consteval bool is_mutable_member(info r);
  consteval bool is_lvalue_reference_qualified(info r);
  consteval bool is_rvalue_reference_qualified(info r);

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

  consteval bool has_internal_linkage(info r);
  consteval bool has_module_linkage(info r);
  consteval bool has_external_linkage(info r);
  consteval bool has_c_language_linkage(info r);
  consteval bool has_linkage(info r);

  consteval bool is_complete_type(info r);
  consteval bool is_enumerable_type(info r);

  consteval bool is_variable(info r);
  consteval bool is_type(info r);
  consteval bool is_namespace(info r);
  consteval bool is_type_alias(info r);
  consteval bool is_namespace_alias(info r);

  consteval bool is_function(info r);
  consteval bool is_conversion_function(info r);
  consteval bool is_operator_function(info r);
  consteval bool is_literal_operator(info r);
  consteval bool is_special_member_function(info r);
  consteval bool is_constructor(info r);
  consteval bool is_default_constructor(info r);
  consteval bool is_copy_constructor(info r);
  consteval bool is_move_constructor(info r);
  consteval bool is_assignment(info r);
  consteval bool is_copy_assignment(info r);
  consteval bool is_move_assignment(info r);
  consteval bool is_destructor(info r);

  consteval bool is_function_parameter(info r);
  consteval bool is_explicit_object_parameter(info r);
  consteval bool has_default_argument(info r);
  consteval bool is_vararg_function(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<info> template_arguments_of(info r);
  consteval vector<info> parameters_of(info r);
  consteval info variable_of(info r);
  consteval info return_type_of(info r);

  // \ref{meta.reflection.access.context}, access control context
  struct access_context;

  // \ref{meta.reflection.access.queries}, member accessibility 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);
  consteval bool has_inaccessible_subobjects(info r, access_context ctx);

  // \ref{meta.reflection.scope}, scope identification
  consteval info current_function();
  consteval info current_class();
  consteval info current_namespace();

  // \ref{meta.reflection.member.queries}, reflection member queries
  consteval vector<info> members_of(info r, access_context ctx);
  consteval vector<info> bases_of(info type, access_context ctx);
  consteval vector<info> static_data_members_of(info type, access_context ctx);
  consteval vector<info> nonstatic_data_members_of(info type, access_context ctx);
  consteval vector<info> subobjects_of(info type, access_context ctx);
  consteval vector<info> 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.annotation}, annotation reflection
  consteval vector<info> annotations_of(info item);
  consteval vector<info> annotations_of_with_type(info item, info type);

  // \ref{meta.reflection.extract}, value extraction
  template<class T>
    consteval T extract(info r);

  // \ref{meta.reflection.substitute}, reflection substitution
  template<class R>
    concept reflection_range = @\seebelow@;

  template<@\libconcept{reflection_range}@ R = initializer_list<info>>
    consteval bool can_substitute(info templ, R&& arguments);
  template<@\libconcept{reflection_range}@ R = initializer_list<info>>
    consteval info substitute(info templ, R&& arguments);

  // \ref{meta.reflection.result}, expression result reflection
  template<class T>
    consteval info reflect_constant(T expr);
  template<class T>
    consteval info reflect_object(T& expr);
  template<class T>
    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<info>>
    consteval info define_aggregate(info type_class, R&& mdescrs);

  // 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_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_structural_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<info>>
    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 type1, info type2);
  consteval bool is_swappable_type(info type);

  consteval bool is_destructible_type(info type);

  template<@\libconcept{reflection_range}@ R = initializer_list<info>>
    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<info>>
    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 type1, info type2);
  consteval bool is_nothrow_swappable_type(info type);

  consteval bool is_nothrow_destructible_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<info>>
    consteval bool is_invocable_type(info type, R&& type_args);
  template<@\libconcept{reflection_range}@ R = initializer_list<info>>
    consteval bool is_invocable_r_type(info type_result, info type, R&& type_args);

  template<@\libconcept{reflection_range}@ R = initializer_list<info>>
    consteval bool is_nothrow_invocable_type(info type, R&& type_args);
  template<@\libconcept{reflection_range}@ R = initializer_list<info>>
    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<info>>
    consteval info common_type(R&& type_args);
  template<@\libconcept{reflection_range}@ R = initializer_list<info>>
    consteval info common_reference(R&& type_args);
  consteval info underlying_type(info type);
  template<@\libconcept{reflection_range}@ R = initializer_list<info>>
    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 bool is_applicable_type(info fn, info tuple);
  consteval bool is_nothrow_applicable_type(info fn, info tuple);
  consteval info apply_result(info fn, info tuple);

  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
When a function or function template specialization $F$ specified in this header
throws a \tcode{meta::exception} $E$,
\tcode{$E$.from()} is a reflection representing $F$ and
\tcode{$E$.where()} is a \tcode{source_location}
representing from where the call to $F$ originated.

\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}
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<class T>
struct X {
  T mem;
};

static_assert(size_of(^^X<int>) == sizeof(int));    // instantiates \tcode{X<int>}
\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 \tcode{V} such that
\tcode{V.data()[V.size()]} equals \tcode{'\textbackslash 0'}.
Each element of the range
$\tcode{V.data()} + \crange{0}{\tcode{V.size()}}$
is a potentially non-unique object with static storage duration that
is usable in constant expressions\iref{intro.object, expr.const};
a pointer to such an element is not suitable for use as
a template argument for a constant template parameter of
pointer type\iref{temp.arg.nontype}.
\begin{example}
\begin{codeblock}
struct C { };

constexpr string_view sv = identifier_of(^^C);
static_assert(sv == "C");
static_assert(sv.data()[0] == 'C');
static_assert(sv.data()[1] == '@\textbackslash{}@0');
\end{codeblock}
\end{example}

\pnum
For the purpose of exposition,
throughout this clause \tcode{\caret\caret\placeholder{E}} is used
to indicate a reflection representing source construct \tcode{\placeholder{E}}.

\rSec2[meta.string.literal]{Checking string literals}

\indexlibraryglobal{is_string_literal}%
\begin{itemdecl}
consteval bool is_string_literal(const char* p);
consteval bool is_string_literal(const wchar_t* p);
consteval bool is_string_literal(const char8_t* p);
consteval bool is_string_literal(const char16_t* p);
consteval bool is_string_literal(const char32_t* p);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
  If \tcode{p} points to an unspecified object\iref{expr.const.core},
  \tcode{false}.
\item
  Otherwise, if \tcode{p} points to a subobject
  of a string literal object\iref{lex.string},
  \tcode{true}.
\item
  Otherwise, \tcode{false}.
\end{itemize}
\end{itemdescr}

\rSec2[meta.define.static]{Promoting to static storage}

\pnum
The functions in this subclause promote compile-time storage into static storage.

\indexlibraryglobal{reflect_constant_string}%
\begin{itemdecl}
template<ranges::@\libconcept{input_range}@ R>
  consteval info reflect_constant_string(R&& r);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{CharT} be \tcode{ranges::range_value_t<R>}.

\pnum
\mandates
\tcode{CharT} is a character type\iref{basic.fundamental}.

\pnum
Let $V$ be the pack of values of type \tcode{CharT}
whose elements are the corresponding elements of \tcode{r},
except that if \tcode{r} is a reference to a string literal object,
then $V$ does not include the terminating \unicode{0000}{null} character of \tcode{r}.

\pnum
Let $P$ be the template parameter object\iref{temp.param}
of type \tcode{const CharT[sizeof...(V) + 1]}
initialized with \tcode{\{$V$..., CharT()\}}.

\pnum
\returns
\tcode{\reflexpr{$P$}}.

\pnum
\begin{note}
$P$ is a potentially non-unique object\iref{intro.object}.
\end{note}
\end{itemdescr}

\indexlibraryglobal{reflect_constant_array}%
\begin{itemdecl}
template<ranges::@\libconcept{input_range}@ R>
  consteval info reflect_constant_array(R&& r);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{U} be \tcode{ranges::range_value_t<R>} and
\tcode{T} be \tcode{remove_all_extents_t<U>}.

\pnum
\mandates
\begin{itemize}
\item \tcode{T} is a structural type\iref{temp.param},
\item \tcode{T} satisfies \libconcept{copy_constructible}, and
\item
if \tcode{U} is not an array type, then
\tcode{is_constructible_v<T, ranges::range_reference_t<R>>} is \tcode{true}.
\end{itemize}

\pnum
Let $V$ be the pack of values of type \tcode{info}
of the same size as \tcode{r},
where the $i^\text{th}$ element is
\begin{itemize}
\item
\tcode{reflect_constant_array(*$\tcode{\placeholder{it}}_i$)}
if \tcode{U} is an array type,
\item
\tcode{reflect_constant(static_cast<T>(*$\tcode{\placeholder{it}}_i$))}
otherwise,
\end{itemize}
and $\tcode{\placeholder{it}}_i$ is an iterator to
the $i^\text{th}$ element of \tcode{r}.

\pnum
Let $P$ be
\begin{itemize}
\item
  the template parameter object\iref{temp.param}
  of type \tcode{const T[sizeof...($V$)]},
  such that \tcode{$P$[$I$]} is template-argument-equivalent\iref{temp.type}
  to the object represented by \tcode{$V$...[$I$]}
  for all $I$ in the range \range{0}{sizeof...($V$)}
  if \tcode{sizeof...($V$) > 0} is \tcode{true}, otherwise
\item
  the template parameter object of type \tcode{const array<T, 0>}
  initialized with \tcode{\{\}}.
\end{itemize}

\pnum
\returns
\tcode{\reflexpr{$P$}}.

\pnum
\throws
Any of
\begin{itemize}
\item
an exception thrown by any operation
on \tcode{r} or
on iterators and sentinels referring to \tcode{r},
\item
an exception thrown
by the evaluation of any argument of \tcode{reflect_constant} or
by any evaluation of \tcode{reflect_constant_array}, or
\item
\tcode{meta::exception}
if any invocation of \tcode{reflect_constant}
would exit via an exception.
\end{itemize}

\pnum
\begin{note}
When \tcode{r} is not empty, $P$ is a potentially non-unique object\iref{intro.object}.
\end{note}
\end{itemdescr}

\indexlibraryglobal{define_static_string}%
\begin{itemdecl}
template<ranges::@\libconcept{input_range}@ R>
  consteval const ranges::range_value_t<R>* define_static_string(R&& r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return meta::extract<const ranges::range_value_t<R>*>(meta::reflect_constant_string(r));
\end{codeblock}
\end{itemdescr}

\indexlibraryglobal{define_static_array}%
\begin{itemdecl}
template<ranges::@\libconcept{input_range}@ R>
  consteval span<const ranges::range_value_t<R>, @\seebelow@> define_static_array(R&& r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
using T = ranges::range_value_t<R>;
meta::info array = meta::reflect_constant_array(r);
if (meta::is_array_type(meta::type_of(array))) {
  return span<const T, @\seebelownc@>(meta::extract<const T*>(array),
                                  meta::extent(meta::type_of(array)));
} else {
  return span<const T, @\seebelow@>(static_cast<const T*>(nullptr), 0);
}
\end{codeblock}

\pnum
\remarks
If \tcode{ranges::size(r)} is a constant expression,
the second template argument of the returned \tcode{span} type
is \tcode{static_cast<size_t>(ranges::size(r))};
otherwise, it is \tcode{dynamic_extent}.
\end{itemdescr}

\indexlibraryglobal{define_static_object}%
\begin{itemdecl}
template<class T>
  consteval const remove_cvref_t<T>* define_static_object(T&& t);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
using U = remove_cvref_t<T>;
if constexpr (meta::is_class_type(^^U) || meta::is_union_type(^^U)) {
  return addressof(meta::extract<const U&>(
                     meta::reflect_constant(std::forward<T>(t))));
} else if constexpr (meta::is_array_type(^^U)) {
  return addressof(meta::extract<const U&>(
                     meta::reflect_constant_array(std::forward<T>(t))));
} else {
  return define_static_array(span(addressof(t), 1)).data();
}
\end{codeblock}

\pnum
\begin{note}
For class types,
\tcode{define_static_object} provides
the address of the template parameter object\iref{temp.param}
that is template-argument equivalent to \tcode{t}.
\end{note}
\end{itemdescr}

\rSec2[meta.reflection.exception]{Class \tcode{exception}}

\indexlibraryglobal{exception}%
\begin{codeblock}
namespace std::meta {
  class exception : public std::exception {
  private:
    optional<string> @\exposidnc{what_}@;     // \expos
    u8string @\exposidnc{u8what_}@;           // \expos
    info @\exposidnc{from_}@;                 // \expos
    source_location @\exposidnc{where_}@;     // \expos

  public:
    consteval exception(u8string_view what, info from,
                        source_location where = source_location::current()) noexcept;

    consteval exception(string_view what, info from,
                        source_location where = source_location::current()) noexcept;

    exception(const exception&) = default;
    exception(exception&&) = default;

    exception& operator=(const exception&) = default;
    exception& operator=(exception&&) = default;

    constexpr const char* what() const noexcept override;
    consteval u8string_view u8what() const noexcept;
    consteval info from() const noexcept;
    consteval source_location where() const noexcept;
  };
}
\end{codeblock}

\pnum
Reflection functions throw exceptions of type \tcode{meta::exception}
to signal an error.
\tcode{meta::exception} is a consteval-only type.

\indexlibraryctor{exception}%
\begin{itemdecl}
consteval exception(u8string_view what, info from,
                    source_location where = source_location::current()) noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Initializes
\exposid{u8what_} with \tcode{what},
\exposid{from_} with \tcode{from}, and
\exposid{where_} with \tcode{where}.
If \tcode{what} can be represented in the ordinary literal encoding,
initializes \exposid{what_} with \tcode{what},
transcoded from UTF-8 to the ordinary literal encoding.
Otherwise, \exposid{what_} is value-initialized.
\end{itemdescr}

\indexlibraryctor{exception}%
\begin{itemdecl}
consteval exception(string_view what, info from,
                    source_location where = source_location::current()) noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\constantwhen
\tcode{what} designates a sequence of characters
that can be encoded in UTF-8.

\pnum
\effects
Initializes
\exposid{what_} with \tcode{what},
\exposid{u8what_} with \tcode{what}
transcoded from the ordinary literal encoding to UTF-8,
%FIXME: Oxford comma before "and"
\exposid{from_} with \tcode{from} and
\exposid{where_} with \tcode{where}.
\end{itemdescr}

\indexlibrarymember{what}{exception}%
\begin{itemdecl}
constexpr const char* what() const noexcept override;
\end{itemdecl}
\begin{itemdescr}
\pnum
\constantwhen
\tcode{\exposid{what_}.has_value()} is \tcode{true}.

\pnum
\returns
\tcode{\exposid{what_}->c_str()}.
\end{itemdescr}

\indexlibrarymember{u8what}{exception}%
\begin{itemdecl}
consteval u8string_view u8what() const noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\exposid{u8what_}.
\end{itemdescr}

\indexlibrarymember{from}{exception}%
\begin{itemdecl}
consteval info from() const noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\exposid{from_}.
\end{itemdescr}

\indexlibrarymember{where}{exception}%
\begin{itemdecl}
consteval source_location where() const noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\exposid{where_}.
\end{itemdescr}

\rSec2[meta.reflection.operators]{Operator representations}

\begin{itemdecl}
enum class @\libglobal{operators}@ {
  @\seebelow@;
};
using enum operators;
\end{itemdecl}

\begin{itemdescr}
\pnum
The enumeration type \tcode{operators} specifies
constants used to identify operators that can be overloaded,
with the meanings listed in~\tref{meta.reflection.operators}.
The values of the constants are distinct.
\end{itemdescr}

%TODO: double-check if this is the right table environment for the job
%TODO: What is the best way to index these enum members?
\begin{floattable}{Enum class \tcode{operators}}{meta.reflection.operators}
{lcc}
\topline
\lhdr{Constant} &
\chdr{Corresponding \grammarterm{operator-function-id}} &
\rhdr{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
\returns
The value of the enumerator from \tcode{operators}
whose corresponding \grammarterm{operator-function-id}
is the unqualified name of the entity represented by \tcode{r}.

\pnum
\throws
\tcode{meta::exception} unless
\tcode{r} represents an operator function or operator function template.
\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
\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.

\pnum
\throws
\tcode{meta::exception} unless
the value of \tcode{op} corresponds to one of the enumerators in \tcode{operators}.
\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 type alias,
  then \tcode{!has_template_arguments(r)}.
\item
  Otherwise, if \tcode{r} represents a type,
  then \tcode{true} if
  \begin{itemize}
  \item
    \tcode{r} represents a cv-unqualified class type and
    \tcode{has_template_arguments(r)} is \tcode{false}, or
  \item
    \tcode{r} represents a cv-unqualified enumeration type.
  \end{itemize}
  Otherwise, \tcode{false}.
\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 the $i^\text{th}$ parameter of a function $F$
  that is an (implicit or explicit) specialization of a templated function $T$
  and the $i^\text{th}$ parameter of the instantiated declaration of $T$
  whose template arguments are those of $F$ would be instantiated from a pack,
  then \tcode{false}.
\item
  Otherwise, if \tcode{r} represents the parameter $P$ of  a function $F$,
  then let $S$ be the set of declarations,
  ignoring any explicit instantiations,
  that are reachable from a point in the evaluation context
  and that declare either $F$ or a templated function
  of which $F$ is a specialization;
  \tcode{true} if
  \begin{itemize}
  \item
    there is a declaration $D$ in $S$ that introduces a name $N$ for either $P$
    or the parameter corresponding to $P$
    in the templated function that $D$ declares and
  \item
    no declaration in $S$ does so using any name other than $N$.
  \end{itemize}
  Otherwise, \tcode{false}.
  \begin{example}
\begin{codeblock}
void fun(int);
constexpr std::meta::info r = parameters_of(^^fun)[0];
static_assert(!has_identifier(r));

void fun(int x);
static_assert(has_identifier(r));

void fun(int x);
static_assert(has_identifier(r));

void poison() {
  void fun(int y);
}
static_assert(!has_identifier(r));
\end{codeblock}
  \end{example}
\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 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, if \tcode{r} represents a data member description
  $(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general};
  \tcode{true} if $N$ is not $\bot$.
  Otherwise, \tcode{false}.
\item
  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
\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 the parameter $P$ of a function $F$,
  then let $S$ be the set of declarations,
  ignoring any explicit instantiations,
  that are reachable from a point in the evaluation context
  and that declare either $F$
  or a templated function of which $F$ is a specialization;
  the name that was introduced by a declaration in $S$
  for the parameter corresponding to $P$.
\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, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general};
  a \tcode{string_view} or \tcode{u8string_view}, respectively,
  containing the identifier $N$.
\end{itemize}

\pnum
\throws
\tcode{meta::exception} unless
\tcode{has_identifier(r)} is \tcode{true}
and the identifier that would be returned (see above)
is representable by $E$.
\end{itemdescr}

\indexlibraryglobal{display_string_of}%
\indexlibraryglobal{u8display_string_of}%
\begin{itemdecl}
consteval string_view display_string_of(info r);
consteval u8string_view u8display_string_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
An
\impldef{the result of \tcode{display_string_of} and \tcode{u8display_string_of}}
\tcode{string_view} or \tcode{u8string_view}, respectively.

\pnum
\recommended
Where possible,
implementations should return a string
suitable for identifying the represented construct.
\end{itemdescr}

\indexlibraryglobal{source_location_of}%
\begin{itemdecl}
consteval source_location source_location_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
If \tcode{r} represents
a value,
a type other than a class type or an enumeration type,
the global namespace, or
a data member description,
then \tcode{source_location\{\}}.
Otherwise, an
\impldef{the value returned by \tcode{std::meta::source_location_of}}
\tcode{source_location} value.

\pnum
\recommended
If \tcode{r} represents an entity with a definition
that is reachable from the evaluation context,
a value corresponding to a definition should be returned.
\end{itemdescr}

\rSec2[meta.reflection.queries]{Reflection queries}

\begin{itemdecl}
consteval bool @\exposid{has-type}@(info r);  // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a
value,
annotation,
object,
variable,
function whose type does not contain an undeduced placeholder type
and that is not a constructor or destructor,
enumerator,
non-static data member,
unnamed bit-field,
direct base class relationship,
data member description, or
function parameter.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{type_of}%
\begin{itemdecl}
consteval info type_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
  If \tcode{r} represents the $i^\text{th}$ parameter of a function $F$,
  then the $i^\text{th}$ type
  in the parameter-type-list of $F$\iref{dcl.fct}.
\item
  Otherwise, if \tcode{r} represents a
  value,
  object,
  variable,
  function,
  non-static data member, or
  unnamed bit-field,
  then the type of what is represented by \tcode{r}.
\item
  Otherwise, if \tcode{r} represents an annotation,
  then \tcode{type_of(constant_of(r))}.
\item
  Otherwise, if \tcode{r} represents
  an enumerator $N$ of an enumeration $E$, then:
  \begin{itemize}
  \item
    If $E$ is defined by a declaration $D$
    that is reachable from 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}, \mathit{ANN})$\iref{class.mem.general},
  a reflection of the type $T$.
\end{itemize}

\pnum
\throws
\tcode{meta::exception} unless
\tcode{\exposid{has-type}(r)} is \tcode{true}.
\end{itemdescr}

\indexlibraryglobal{object_of}%
\begin{itemdecl}
consteval info object_of(info r);
\end{itemdecl}

\begin{itemdescr}
\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}

\pnum
\throws
\tcode{meta::exception} unless
\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.init}, or
  \item
    the lifetime of $R$ began within the core constant expression
    currently under evaluation.
  \end{itemize}
\end{itemize}

\pnum
\begin{example}
\begin{codeblock}
int x;
int& y = x;

static_assert(^^x != ^^y);                          // OK, \tcode{r} and \tcode{y} are different variables, so their
                                                    // reflections compare different
static_assert(object_of(^^x) == object_of(^^y));    // OK, because \tcode{y} is a reference
                                                    // to \tcode{x}, their underlying objects are the same
\end{codeblock}
\end{example}
\end{itemdescr}

\indexlibraryglobal{constant_of}%
\begin{itemdecl}
consteval info constant_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let $R$ be a constant expression of type \tcode{info}
such that \tcode{$R$ == r} is \tcode{true}.
If \tcode{r} represents an annotation,
then let $C$ be its underlying constant.

\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (is_annotation(@$R$@)) {
  return @$C$@;
} else if constexpr (is_array_type(type_of(@$R$@))) {
  return reflect_constant_array([: @$R$@ :]);
} else if constexpr (is_function_type(type_of(@$R$@))) {
  return reflect_function([: @$R$@ :]);
} else {
  return reflect_constant([: @$R$@ :]);
}
\end{codeblock}

\pnum
\throws
\tcode{meta::exception} unless
either \tcode{r} represents an annotation or
\tcode{[: $R$ :]} is a valid
\grammarterm{splice-expression}\iref{expr.prim.splice}.

\pnum
\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) ==               // OK, both \tcode{constant_of(\reflexpr{x})} and
              constant_of(^^y));                // \tcode{constant_of(\reflexpr{y})} represent the value \tcode{0}

static_assert(constant_of(^^x) ==               // OK, likewise
              reflect_constant(0));

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) !=               // OK, template parameter object that is
              reflect_object(s));               // template-argument-equivalent to \tcode{s}
                                                // is a different object than \tcode{s}

static_assert(constant_of(^^s) ==
              constant_of(reflect_object(s)));

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_user_provided}%
\indexlibraryglobal{is_user_declared}%
\begin{itemdecl}
consteval bool is_user_provided(info r);
consteval bool is_user_declared(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a function that is
user-provided or user-declared\iref{dcl.fct.def.default}, respectively.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_explicit}%
\begin{itemdecl}
consteval bool is_explicit(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a member function that is declared explicit.
Otherwise, \tcode{false}.
\begin{note}
If \tcode{r} represents a member function template that is declared explicit,
\tcode{is_explicit(r)} is still \tcode{false}
because in general,
such queries for templates cannot be answered.
\end{note}
\end{itemdescr}

\indexlibraryglobal{is_noexcept}%
\begin{itemdecl}
consteval bool is_noexcept(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a \tcode{noexcept} function type
or a function with a non-throwing exception specification\iref{except.spec}.
Otherwise, \tcode{false}.
\begin{note}
If \tcode{r} represents a function template that is declared \tcode{noexcept},
\tcode{is_noexcept(r)} is still \tcode{false}
because in general,
such queries for templates cannot be answered.
\end{note}
\end{itemdescr}

\indexlibraryglobal{is_bit_field}%
\begin{itemdecl}
consteval bool is_bit_field(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a bit-field,
or if \tcode{r} represents a data member description
$(T, N, A, W, \mathit{NUA},\brk{} \mathit{ANN})$\iref{class.mem.general}
for which $W$ is not $\bot$.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_enumerator}%
\indexlibraryglobal{is_annotation}%
\begin{itemdecl}
consteval bool is_enumerator(info r);
consteval bool is_annotation(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents an enumerator or annotation, respectively.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_const}%
\indexlibraryglobal{is_volatile}%
\begin{itemdecl}
consteval bool is_const(info r);
consteval bool is_volatile(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
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 const or volatile type, respectively,
or a const- or volatile-qualified function type, respectively.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_mutable_member}%
\begin{itemdecl}
consteval bool is_mutable_member(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a \tcode{mutable} non-static data member.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_lvalue_reference_qualified}%
\indexlibraryglobal{is_rvalue_reference_qualified}%
\begin{itemdecl}
consteval bool is_lvalue_reference_qualified(info r);
consteval bool is_rvalue_reference_qualified(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let $T$ be \tcode{type_of(r)} if \tcode{\exposid{has-type}(r)} is \tcode{true}.
Otherwise, let $T$ be \tcode{dealias(r)}.

\pnum
\returns
\tcode{true} if $T$ represents an
lvalue- or rvalue-qualified function type, respectively.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{has_static_storage_duration}%
\indexlibraryglobal{has_thread_storage_duration}%
\indexlibraryglobal{has_automatic_storage_duration}%
\begin{itemdecl}
consteval bool has_static_storage_duration(info r);
consteval bool has_thread_storage_duration(info r);
consteval bool has_automatic_storage_duration(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents an object or variable that has
static, thread, or automatic storage duration, respectively\iref{basic.stc}.
Otherwise, \tcode{false}.
\begin{note}
It is not possible to have a reflection
representing an object or variable having dynamic storage duration.
\end{note}
\end{itemdescr}

\indexlibraryglobal{has_internal_linkage}%
\indexlibraryglobal{has_module_linkage}%
\indexlibraryglobal{has_external_linkage}%
\indexlibraryglobal{has_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_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,
external linkage, or
any linkage, respectively\iref{basic.link}.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{has_c_language_linkage}%
\begin{itemdecl}
consteval bool has_c_language_linkage(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a
variable,
function, or
function type
with C language linkage.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_complete_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}.

\pnum
\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<int>(E::A) == 2);
\end{codeblock}
\end{example}
\end{itemdescr}

\indexlibraryglobal{is_variable}%
\begin{itemdecl}
consteval bool is_variable(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a variable.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_type}%
\indexlibraryglobal{is_namespace}%
\begin{itemdecl}
consteval bool is_type(info r);
consteval bool is_namespace(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents an entity
whose underlying entity is a type or namespace, respectively.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_type_alias}%
\indexlibraryglobal{is_namespace_alias}%
\begin{itemdecl}
consteval bool is_type_alias(info r);
consteval bool is_namespace_alias(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a type alias or namespace alias, respectively.
Otherwise, \tcode{false}.
\begin{note}
A specialization of an alias template is a type alias.
\end{note}
\end{itemdescr}

\indexlibraryglobal{is_function}%
\begin{itemdecl}
consteval bool is_function(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a function.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_conversion_function}%
\indexlibraryglobal{is_operator_function}%
\indexlibraryglobal{is_literal_operator}%
\begin{itemdecl}
consteval bool is_conversion_function(info r);
consteval bool is_operator_function(info r);
consteval bool is_literal_operator(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a function that is a
conversion function\iref{class.conv.fct},
operator function\iref{over.oper}, or
literal operator\iref{over.literal}, respectively.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_special_member_function}%
\indexlibraryglobal{is_constructor}%
\indexlibraryglobal{is_default_constructor}%
\indexlibraryglobal{is_copy_constructor}%
\indexlibraryglobal{is_move_constructor}%
\indexlibraryglobal{is_assignment}%
\indexlibraryglobal{is_copy_assignment}%
\indexlibraryglobal{is_move_assignment}%
\indexlibraryglobal{is_destructor}%
\begin{itemdecl}
consteval bool is_special_member_function(info r);
consteval bool is_constructor(info r);
consteval bool is_default_constructor(info r);
consteval bool is_copy_constructor(info r);
consteval bool is_move_constructor(info r);
consteval bool is_assignment(info r);
consteval bool is_copy_assignment(info r);
consteval bool is_move_assignment(info r);
consteval bool is_destructor(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a function that is a
special member function\iref{special},
a constructor,
a default constructor,
a copy constructor,
a move constructor,
an assignment operator,
a copy assignment operator,
a move assignment operator, or
a destructor, respectively.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_function_parameter}%
\begin{itemdecl}
consteval bool is_function_parameter(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a function parameter.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_explicit_object_parameter}%
\begin{itemdecl}
consteval bool is_explicit_object_parameter(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a function parameter
that is an explicit object parameter\iref{dcl.fct}.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{has_default_argument}%
\begin{itemdecl}
consteval bool has_default_argument(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
If \tcode{r} represents a parameter $P$ of a function $F$, then:
\begin{itemize}
\item
  If $F$ is a specialization of a templated function $T$,
  then \tcode{true} if there exists a declaration $D$ of $T$
  that is reachable from a point in the evaluation context
  and $D$ specifies a default argument
  for the parameter of $T$ corresponding to $P$.
  Otherwise, \tcode{false}.
\item
  Otherwise, if there exists a declaration $D$ of $F$
  that is reachable from a point in the evaluation context
  and $D$ specifies a default argument for $P$,
  then \tcode{true}.
\end{itemize}
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_vararg_function}%
\begin{itemdecl}
consteval bool is_vararg_function(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a function or function type
that is a vararg function\iref{dcl.fct}.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_template}%
\begin{itemdecl}
consteval bool is_template(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a
function template,
class template,
variable template,
alias template, or
concept.
Otherwise, \tcode{false}.

\pnum
\begin{note}
A template specialization is not a template.
For example,
\tcode{is_template(\brk{}\reflexpr{std::vector})} is \tcode{true}
but \tcode{is_template(\brk{}\reflexpr{std::vector<int>})} 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,
operator function template,
literal operator template,
constructor template, or
concept, respectively.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_value}%
\indexlibraryglobal{is_object}%
\begin{itemdecl}
consteval bool is_value(info r);
consteval bool is_object(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a value or object, respectively.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_structured_binding}%
\begin{itemdecl}
consteval bool is_structured_binding(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a structured binding.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{is_class_member}%
\indexlibraryglobal{is_namespace_member}%
\indexlibraryglobal{is_nonstatic_data_member}%
\indexlibraryglobal{is_static_member}%
\indexlibraryglobal{is_base}%
\begin{itemdecl}
consteval bool is_class_member(info r);
consteval bool is_namespace_member(info r);
consteval bool is_nonstatic_data_member(info r);
consteval bool is_static_member(info r);
consteval bool is_base(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a
class member,
namespace member,
non-static data member,
static member, or
direct base class relationship, respectively.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{has_default_member_initializer}%
\begin{itemdecl}
consteval bool has_default_member_initializer(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{r} represents a non-static data member
that has a default member initializer.
Otherwise, \tcode{false}.
\end{itemdescr}

\indexlibraryglobal{has_parent}%
\begin{itemdecl}
consteval bool has_parent(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
  If \tcode{r} represents the global namespace,
  then \tcode{false}.
\item
  Otherwise, if \tcode{r} represents an entity that has C language linkage\iref{dcl.link},
  then \tcode{false}.
\item
  Otherwise, if \tcode{r} represents an entity 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 entity 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
\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 operator 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}

\pnum
\throws
\tcode{meta::exception} unless
\tcode{has_parent(r)} is \tcode{true}.

\pnum
\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{dealias}%
\begin{itemdecl}
consteval info dealias(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
If \tcode{r} represents an entity, then
a reflection representing the underlying entity of what \tcode{r} represents.
Otherwise, \tcode{r}.

\pnum
\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
\returns
A reflection of the template of the specialization represented by \tcode{r}.

\pnum
\throws
\tcode{meta::exception} unless
\tcode{has_template_arguments(r)} is \tcode{true}.
\end{itemdescr}

\indexlibraryglobal{template_arguments_of}%
\begin{itemdecl}
consteval vector<info> template_arguments_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
A \tcode{vector} containing reflections
of the template arguments
of the template specialization represented by \tcode{r},
in the order in which they appear in the corresponding template argument list.
For a given template argument $A$,
its corresponding reflection $R$ is determined as follows:
\begin{itemize}
\item
  If $A$ denotes a type or type alias,
  then $R$ is a reflection representing the underlying entity of $A$.
  \begin{note}
  $R$ always represents a type, never a type alias.
  \end{note}
\item
  Otherwise, if $A$ denotes a
  class template,
  variable template,
  concept, or
  alias template,
  then $R$ is a reflection representing $A$.
\item
  Otherwise, $A$ is a constant template argument\iref{temp.arg.nontype}.
  Let $P$ be the corresponding template parameter.
  \begin{itemize}
  \item
    If $P$ has reference type,
    then $R$ is a reflection
    representing the object or function referred to by $A$.
  \item
    Otherwise, if $P$ has class type,
    then $R$ represents the corresponding template parameter object.
  \item
    Otherwise, $R$ is a reflection representing the value of $A$.
  \end{itemize}
\end{itemize}

\pnum
\throws
\tcode{meta::exception} unless
\tcode{has_template_arguments(r)} is \tcode{true}.

\pnum
\begin{example}
\begin{codeblock}
template<class T, class U = T> struct Pair { };
template<class T> struct Pair<char, T> { };
template<class T> using PairPtr = Pair<T*>;

static_assert(template_of(^^Pair<int>) == ^^Pair);
static_assert(template_of(^^Pair<char, char>) == ^^Pair);
static_assert(template_arguments_of(^^Pair<int>).size() == 2);
static_assert(template_arguments_of(^^Pair<int>)[0] == ^^int);

static_assert(template_of(^^PairPtr<int>) == ^^PairPtr);
static_assert(template_arguments_of(^^PairPtr<int>).size() == 1);

struct S { };
int i;
template<int, int&, S, template<class> 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}

\indexlibraryglobal{parameters_of}%
\begin{itemdecl}
consteval vector<info> parameters_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
  If \tcode{r} represents a function $F$,
  then a \tcode{vector} containing reflections of the parameters of $F$,
  in the order in which they appear in a declaration of $F$.
\item
  Otherwise, \tcode{r} represents a function type $T$;
  a \tcode{vector} containing reflections of the types
  in parameter-type-list\iref{dcl.fct} of $T$,
  in the order in which they appear in the parameter-type-list.
\end{itemize}

\pnum
\throws
\tcode{meta::exception} unless
\tcode{r} represents a function or a function type.
\end{itemdescr}

\indexlibraryglobal{variable_of}%
\begin{itemdecl}
consteval info variable_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
The reflection of the parameter variable corresponding to \tcode{r}.

\pnum
\throws
\tcode{meta::exception} unless
\begin{itemize}
\item
  \tcode{r} represents a parameter of a function $F$ and
\item
  there is a point $P$ in the evaluation context
  for which the innermost non-block scope enclosing $P$
  is the function parameter scope\iref{basic.scope.param}
  associated with $F$.
\end{itemize}
\end{itemdescr}

\indexlibraryglobal{return_type_of}%
\begin{itemdecl}
consteval info return_type_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
The reflection of the return type
of the function or function type represented by \tcode{r}.

\pnum
\throws
\tcode{meta::exception} unless
either \tcode{r} represents a function
and \tcode{\exposid{has-type}(r)} is \tcode{true}
or \tcode{r} represents a function type.
\end{itemdescr}

\rSec2[meta.reflection.scope]{Scope identification}

\pnum
The functions in this subclause retrieve information
about where in the program they are invoked.

\pnum
None of the functions in this subclause
is 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 scope
      introduced by a \grammarterm{consteval-block-declaration}.
    \end{itemize}
  \item
    Otherwise, $P$.
\end{itemize}

\pnum
Given a scope $S$,
let \tcode{\exposid{ctx-scope}($S$)} be the following scope:
\begin{itemize}
\item
  If $S$ is a class scope or namespace scope,
  $S$.
\item
  Otherwise, if $S$ is a function parameter scope
  introduced by the declaration of a function,
  $S$.
\item
  Otherwise, if $S$ is a lambda scope
  introduced by a \grammarterm{lambda-expression} $L$,
  the function parameter scope
  corresponding to the call operator of the closure type of $L$.
\item
  Otherwise, \tcode{\exposid{ctx-scope}($S'$)},
  where $S'$ is the parent scope of $S$.
\end{itemize}

\pnum
Let \tcode{\exposid{CURRENT-SCOPE}($P$)} for a point $P$ be
a reflection representing the function, class, or namespace
whose corresponding
function parameter scope,
class scope, or
namespace scope, respectively,
is \tcode{\exposid{ctx-scope}($S$)},
where $S$ is the immediate scope of \tcode{\exposid{eval-point}($P$)}.

\indexlibraryglobal{current_function}%
\begin{itemdecl}
consteval info current_function();
\end{itemdecl}

\begin{itemdescr}
\pnum
An invocation of \tcode{current_function} that appears at a program point $P$
is value-dependent\iref{temp.dep.constexpr}
if \tcode{\exposid{eval-point}($P$)}
is enclosed by a scope corresponding to a templated entity.

\pnum
Let $S$ be \tcode{\exposid{CURRENT-SCOPE}($P$)},
where $P$ is the point at which the invocation of
\tcode{current_function} lexically appears.

\pnum
\returns
$S$.

\pnum
\throws
\tcode{meta::exception} unless $S$ represents a function.
\end{itemdescr}

\indexlibraryglobal{current_class}%
\begin{itemdecl}
consteval info current_class();
\end{itemdecl}

\begin{itemdescr}
\pnum
An invocation of \tcode{current_class} that appears at a program point $P$
is value-dependent\iref{temp.dep.constexpr}
if \tcode{\exposid{eval-point}($P$)}
is enclosed by a scope corresponding to a templated entity.

\pnum
Let $S$ be \tcode{\exposid{CURRENT-SCOPE}($P$)}
where $P$ is the point at which the invocation of
\tcode{current_class} lexically appears.

\pnum
\returns
$S$ if $S$ represents a class.
Otherwise, \tcode{parent_of($S$)}.

\pnum
\throws
\tcode{meta::exception} unless $S$ represents
either a class or a member function.
\end{itemdescr}

\indexlibraryglobal{current_namespace}%
\begin{itemdecl}
consteval info current_namespace();
\end{itemdecl}

\begin{itemdescr}
\pnum
An invocation of \tcode{current_namespace} that appears at a program point $P$
is value-dependent\iref{temp.dep.constexpr}
if \tcode{\exposid{eval-point}($P$)}
is enclosed by a scope corresponding to a templated entity.

\pnum
Let $S$ be \tcode{\exposid{CURRENT-SCOPE}($P$)}
where $P$ is the point at which the invocation of
\tcode{current_namespace} lexically appears.

\pnum
\returns
$S$ if $S$ represents a namespace.
Otherwise, a reflection representing the nearest enclosing namespace
of the entity represented by $S$.
\end{itemdescr}

\rSec2[meta.reflection.access.context]{Access control context}

\pnum
The class \tcode{access_context}
represents a namespace, 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.

\indexlibraryglobal{access_context}%
\begin{codeblock}
namespace std::meta {
  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{codeblock}

\pnum
The type \tcode{access_context} is a structural, consteval-only, non-aggregate type.
Two values \tcode{ac1} and \tcode{ac2} of type \tcode{access_context}
are template-argument-equivalent\iref{temp.type}
if \tcode{ac1.scope()} and \tcode{ac2.scope()} are template-argument-equivalent
and \tcode{ac1.designating_class()} and \tcode{ac2.designating_class()}
are template-argument-equivalent.

\begin{itemdecl}
consteval info @\libmember{scope}{access_context}@() const;
consteval info @\libmember{designating_class}{access_context}@() const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
The \tcode{access_context}'s associated scope
and designating class, respectively.
\end{itemdescr}

\begin{itemdecl}
static consteval access_context @\libmember{current}{access_context}@() noexcept;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
An \tcode{access_context} whose designating class is the null reflection
and whose scope is \tcode{\exposid{CURRENT-SCOPE}($P$)},
where $P$ is the point at which the invocation of \tcode{current} lexically appears.

\pnum
\remarks
\tcode{current} is not an addressable function\iref{namespace.std}.
An invocation of \tcode{current} that appears at a program point $P$
is value-dependent\iref{temp.dep.constexpr}
if \tcode{\exposid{eval-point}\brk{}(\brk{}$P$)} is enclosed by a scope
corresponding to a templated entity.

\pnum
\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());
  static_assert(Agg{}.eq());
  static_assert(B(1).s == ^^B);
  static_assert(is_constructor(B{1, 2}.s) && parent_of(B{1, 2}.s) == ^^B);
  static_assert(is_constructor(C{1, 2}.s) && parent_of(C{1, 2}.s) == ^^B);

  auto fn() -> [:is_namespace(access_context::current().scope()) ? ^^int : ^^bool:];
  static_assert(type_of(^^fn) == ^^auto()->int);

  template<auto R>
    struct TCls {
      consteval bool fn()
        requires (is_type(access_context::current().scope())) {
          return true;                  // OK, scope is \tcode{TCls<R>}.
        }
    };
  static_assert(TCls<0>{}.fn());
}
\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}
consteval access_context @\libmember{via}{access_context}@(info cls) const;
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
An \tcode{access_context} whose scope is \tcode{this->scope()}
and whose designating class is \tcode{cls}.

\pnum
\throws
\tcode{meta::exception} unless
\tcode{cls} is either the null reflection
or a reflection of a complete class type.
\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
Let \tcode{\exposid{DESIGNATING-CLS}(r, ctx)} be:
\begin{itemize}
\item If \tcode{ctx.designating_class()} represents a class $C$, then $C$.
\item Otherwise, \tcode{\exposid{PARENT-CLS}(r)}.
\end{itemize}

\pnum
\returns
\begin{itemize}
\item
  If \tcode{r} represents an unnamed bit-field $F$,
  then \tcode{is_accessible($\tcode{r}_H$, ctx)},
  where $\tcode{r}_H$ represents a hypothetical non-static data member
  of the class represented by \tcode{\exposid{PARENT-CLS}(r)}
  with the same access as $F$.
  \begin{note}
  Unnamed bit-fields are treated as class members
  for the purpose of \tcode{is_accessible}.
  \end{note}
\item
  Otherwise, if \tcode{r} does not represent a class member
  or a direct base class relationship,
  then \tcode{true}.
\item
  Otherwise, if \tcode{r} represents
  \begin{itemize}
  \item
    a class member that is not a (possibly indirect or variant)
    member of \tcode{\exposid{DESIG\-NATING-CLS}(\brk{}r, ctx)} or
  \item
    a direct base class relationship such that \tcode{parent_of(r)}
    does not represent \tcode{\exposid{DESIG\-NATING-CLS}(\brk{}r, ctx)}
    or a (direct or indirect) base class thereof,
  \end{itemize}
  then \tcode{false}.
\item
  Otherwise, if \tcode{ctx.scope()} is the null reflection,
  then \tcode{true}.
\item
  Otherwise, letting $P$ be a program point whose immediate scope is the
  function parameter scope, class scope, or namespace scope
  corresponding to the
  function, class, or namespace
  represented by \tcode{ctx.scope()}:
  \begin{itemize}
  \item
    If \tcode{r} represents a direct base class relationship $(D, B)$,
    then \tcode{true} if base class $B$ of \tcode{\exposid{DESIG\-NATING-CLS}(\brk{}r, ctx)}
    is accessible at $P$\iref{class.access.base};
    otherwise \tcode{false}.
  \item
    Otherwise, \tcode{r} represents a class member $M$;
    \tcode{true} if $M$ would be accessible at $P$
    with the designating class\iref{class.access.base} as \tcode{\exposid{DESIG\-NATING-CLS}(r, ctx)}
    if the effect of any \grammarterm{using-declaration}s\iref{namespace.udecl} were ignored.
    Otherwise, \tcode{false}.
  \end{itemize}
\end{itemize}
\begin{note}
The definitions of when a class member or base class is accessible from a point $P$
do not consider whether a declaration of that entity is reachable from $P$.
\end{note}

\pnum
\throws
\tcode{meta::exception} if
  \tcode{r} represents a class member
  for which \tcode{\exposid{PARENT-CLS}(r)} is an incomplete class.

\pnum
\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()));
static_assert(!is_accessible(Cls::r, access_context::current()));
static_assert(is_accessible(Cls::r, access_context::unchecked()));
\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
\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}.

\pnum
\throws
\tcode{meta::exception} if
\begin{itemize}
\item
  the evaluation of
  \tcode{nonstatic_data_members_of(r, access_context::unchecked())}
  would exit via an exception or
\item
  \tcode{r} represents a closure type.
\end{itemize}
\end{itemdescr}

\indexlibraryglobal{has_inaccessible_bases}%
\begin{itemdecl}
consteval bool has_inaccessible_bases(info r, access_context ctx);
\end{itemdecl}

\begin{itemdescr}
\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}.

\pnum
\throws
\tcode{meta::exception} if the evaluation of
\tcode{bases_of(r, access_context::unchecked())}
would exit via an exception.
\end{itemdescr}

\indexlibraryglobal{has_inaccessible_subobjects}%
\begin{itemdecl}
consteval bool has_inaccessible_subobjects(info r, access_context ctx);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return has_inaccessible_bases(r, ctx) || has_inaccessible_nonstatic_data_members(r, ctx);
\end{codeblock}
\end{itemdescr}

\rSec2[meta.reflection.member.queries]{Reflection member queries}

\indexlibraryglobal{members_of}%
\begin{itemdecl}
consteval vector<info> members_of(info r, access_context ctx);
\end{itemdecl}

\begin{itemdescr}
\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-eligible}
whether declarations of other members of a closure type $Q$
are $Q$-members-of-eligible.

\pnum
A member $M$ of a class or namespace $Q$ is
\term{$Q$-members-of-representable} from a point $P$
if a $Q$-members-of-eligible declaration of $M$ members-of-precedes $P$,
and $M$ is
\begin{itemize}
\item
  a class or enumeration type,
\item
  a type alias,
\item
  a class template, function template,
  variable template, alias template, or concept,
\item
  a variable or reference $V$
  for which the type of $V$ does not contain an undeduced placeholder type,
\item
  a function $F$ for which
  \begin{itemize}
  \item
    the type of $F$  does not contain an undeduced placeholder type,
  \item
    the constraints (if any) of $F$ are satisfied, and
  \item
    if $F$ is a prospective destructor,
    $F$ is the selected destructor\iref{class.dtor},
  \end{itemize}
\item
  a non-static data member,
\item
  a namespace, or
\item
  a namespace alias.
\end{itemize}
\begin{note}
Examples of direct members that are not $Q$-members-of-representable
for any entity $Q$ include:
unscoped enumerators\iref{enum},
partial specializations of templates\iref{temp.spec.partial}, and
closure types\iref{expr.prim.lambda.closure}.
\end{note}

\pnum
\returns
A \tcode{vector} containing reflections of all members $M$
of the entity $Q$ represented by \tcode{dealias(r)} for which
\begin{itemize}
\item
  $M$ is $Q$-members-of-representable
  from some point in the evaluation context and
\item
  \tcode{is_accessible(\reflexpr{$M$}, ctx)} is \tcode{true}.
\end{itemize}
If \tcode{dealias(r)} represents a class $C$,
then the \tcode{vector} also contains reflections
representing all unnamed bit-fields $B$
whose declarations inhabit the class scope corresponding to $C$
for which \tcode{is_accessible(\reflexpr{$B$}, ctx)} is \tcode{true}.
Reflections of class members and unnamed bit-fields that are declared
appear in the order in which they are declared.
\begin{note}
Base classes are not members.
Implicitly-declared special members
appear after any user-declared members\iref{special}.
\end{note}

\pnum
\throws
\tcode{meta::exception} unless
\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
\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<info> bases_of(info type, access_context ctx);
\end{itemdecl}

\begin{itemdescr}
\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 $B$, if any,
of $C$ such that \tcode{is_accessible(\reflexpr{$B$}, ctx)} 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$.

\pnum
\throws
\tcode{meta::exception} unless
\tcode{dealias(type)} represents a class type
that is complete from some point in the evaluation context.
\end{itemdescr}

\indexlibraryglobal{static_data_members_of}%
\begin{itemdecl}
consteval vector<info> static_data_members_of(info type, access_context ctx);
\end{itemdecl}

\begin{itemdescr}
\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.

\pnum
\throws
\tcode{meta::exception} unless
\tcode{dealias(type)} represents a class type
that is complete from some point in the evaluation context.
\end{itemdescr}


\indexlibraryglobal{nonstatic_data_members_of}%
\begin{itemdecl}
consteval vector<info> nonstatic_data_members_of(info type, access_context ctx);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
A \tcode{vector} containing each element \tcode{e} of \tcode{members_of(type, ctx)}
such that \tcode{is_nonstatic_data_member(e)} is \tcode{true},
preserving their order.

\pnum
\throws
\tcode{meta::exception} unless
\tcode{dealias(type)} represents a class type
that is complete from some point in the evaluation context.
\end{itemdescr}

\indexlibraryglobal{subobjects_of}%
\begin{itemdecl}
consteval vector<info> subobjects_of(info type, access_context ctx);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
A \tcode{vector} containing each element of \tcode{bases_of(type, ctx)}
followed by each element of \tcode{non\-static_data_mem\-bers_of(\brk{}type,\brk{} ctx)},
preserving their order.

\pnum
\throws
\tcode{meta::exception} unless
\tcode{dealias(type)} represents a class type
that is complete from some point in the evaluation context.
\end{itemdescr}

\indexlibraryglobal{enumerators_of}%
\begin{itemdecl}
consteval vector<info> enumerators_of(info type_enum);
\end{itemdecl}

\begin{itemdescr}
\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.

\pnum
\throws
\tcode{meta::exception} unless
\tcode{dealias(type_enum)} represents an enumeration type,
and \tcode{is_enumerable_type(\brk{}type_enum)} is \tcode{true}.
\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
Let $V$ be the offset in bits from the beginning of a complete object
of the type represented by \tcode{parent_of(r)}
to the subobject associated with the construct represented by \tcode{r}.

\pnum
\returns
\tcode{\{$V$ / CHAR_BIT, $V$ \% CHAR_BIT\}}.

\pnum
\throws
\tcode{meta::exception} unless
\tcode{r} represents a non-static data member,
unnamed bit-field, or
direct base class relationship $(D, B)$
for which either $B$ is not a virtual base class
or $D$ is not an abstract class.
\end{itemdescr}

\indexlibraryglobal{size_of}%
\begin{itemdecl}
consteval size_t size_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
If
\begin{itemize}
\item \tcode{r} represents a non-static data member of type $T$ or
a data member description $(T, N, A, W, \mathit{NUA},\brk{} \mathit{ANN})$ 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(add_pointer(\brk{}\reflexpr{$T$}))} otherwise.
Otherwise, \tcode{size_of(type_of(r))}.
\begin{note}
It is possible that while \tcode{sizeof(char)\brk{} == size_of(\reflexpr{char})}
is \tcode{true},
that \tcode{sizeof(char\&)\brk{} == size_of(\brk{}\reflexpr{char}\&)}
is \tcode{false}.
If \tcode{b} represents a direct base class relationship of an empty base class,
then \tcode{size_of(b) > 0} is \tcode{true}.
\end{note}

\pnum
\throws
\tcode{meta::exception} unless
all of the following conditions are met:
\begin{itemize}
\item
\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}, \mathit{ANN})$\iref{class.mem.general}
where $W$ is $\bot$.
\item
If \tcode{dealias(r)} represents a type,
then \tcode{is_complete_type(r)} is \tcode{true}.
\end{itemize}
\end{itemdescr}

\indexlibraryglobal{alignment_of}%
\begin{itemdecl}
consteval size_t alignment_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
  If \tcode{dealias(r)} represents a type $T$,
  then \tcode{alignment_of(add_pointer(r))} if $T$ is a reference type
  and the alignment requirement of $T$ otherwise.
\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 $M$ of a class $C$,
  then the alignment of the direct member subobject
  corresponding to $M$ of a complete object of type $C$.
\item
  Otherwise, \tcode{r} represents a data member description
  $(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general}.
  If $A$ is not $\bot$,
  then the value $A$.
  Otherwise, \tcode{alignment_of(\reflexpr{$T$})}.
\end{itemize}

\pnum
\throws
\tcode{meta::exception} unless
all of the following conditions are met:
\begin{itemize}
\item
\tcode{dealias(r)} is a reflection of a
type,
object,
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}, \mathit{ANN})$\iref{class.mem.general}
where $W$ is $\bot$.
\item
If \tcode{dealias(r)} represents a type,
then \tcode{is_complete_type(r)} is \tcode{true}.
\end{itemize}
\end{itemdescr}

\indexlibraryglobal{bit_size_of}%
\begin{itemdecl}
consteval size_t bit_size_of(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
  If \tcode{r} represents
  an unnamed bit-field
  or a non-static data member that is a bit-field
  with width $W$,
  then $W$.
\item
  Otherwise, if \tcode{r} represents a data member description
  $(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\iref{class.mem.general}
  and $W$ is not $\bot$,
  then $W$.
\item
  Otherwise, \tcode{CHAR_BIT * size_of(r)}.
\end{itemize}

\pnum
\throws
\tcode{meta::exception} unless
all of the following conditions are met:
\begin{itemize}
\item
\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.
\item
If \tcode{dealias(r)} represents a type,
then \tcode{is_complete_type(r)} is \tcode{true}.
\end{itemize}
\end{itemdescr}

\rSec2[meta.reflection.annotation]{Annotation reflection}

\indexlibraryglobal{annotations_of}%
\begin{itemdecl}
consteval vector<info> annotations_of(info item);
\end{itemdecl}

\begin{itemdescr}
\pnum
For a function $F$,
let $S(F)$ be the set of declarations,
ignoring any explicit instantiations,
that declare either $F$ or
a templated function of which $F$ is a specialization.

\pnum
\returns
A \tcode{vector} containing all of the reflections $R$
representing each annotation applying to:
\begin{itemize}
\item
  if \tcode{item} represents a function parameter $P$ of a function $F$,
  then the declaration of $P$ in each declaration of $F$ in $S(F)$,
\item
  otherwise, if \tcode{item} represents a function $F$,
  then each declaration of $F$ in $S(F)$,
\item
  otherwise, if \tcode{item} represents
  a direct base class relationship $(D, B)$,
  then the corresponding \grammarterm{base-specifier}
  in the definition of $D$,
\item
  otherwise, each declaration of the entity represented by \tcode{item},
\end{itemize}
such that each specified declaration is reachable from either
some point in the evaluation context\iref{expr.const.reflect} or
a point immediately following the \grammarterm{class-specifier}
of the outermost class for which such a point is in a complete-class context.
For any two reflections $R_1$ and $R_2$ in the returned \tcode{vector},
if the annotation represented by $R_1$ precedes the annotation represented by $R_2$,
then $R_1$ appears before $R_2$.
If $R_1$ and $R_2$ represent annotations from the same translation unit $T$,
any element in the returned \tcode{vector} between $R_1$ and $R_2$
represents an annotation from $T$.
\begin{note}
The order in which two annotations appear is otherwise unspecified.
\end{note}

\pnum
\throws
\tcode{meta::exception} unless
\tcode{item} represents a
type,
type alias,
variable,
function,
function parameter,
namespace,
enumerator,
direct base class relationship, or
non-static data member.

\pnum
\begin{example}
\begin{codeblock}
[[=1]] void f();
[[=2, =3]] void g();
void g [[=4]] ();

static_assert(annotations_of(^^f).size() == 1);
static_assert(annotations_of(^^g).size() == 3);
static_assert([: constant_of(annotations_of(^^g)[0]) :] == 2);
static_assert(extract<int>(annotations_of(^^g)[1]) == 3);
static_assert(extract<int>(annotations_of(^^g)[2]) == 4);

struct Option { bool value; };

struct C {
  [[=Option{true}]] int a;
  [[=Option{false}]] int b;
};

static_assert(extract<Option>(annotations_of(^^C::a)[0]).value);
static_assert(!extract<Option>(annotations_of(^^C::b)[0]).value);

template<class T>
  struct [[=42]] D { };

constexpr std::meta::info a1 = annotations_of(^^D<int>)[0];
constexpr std::meta::info a2 = annotations_of(^^D<char>)[0];
static_assert(a1 != a2);
static_assert(constant_of(a1) == constant_of(a2));

[[=1]] int x, y;
static_assert(annotations_of(^^x)[0] == annotations_of(^^y)[0]);
\end{codeblock}
\end{example}
\end{itemdescr}

\indexlibraryglobal{annotations_of_with_type}%
\begin{itemdecl}
consteval vector<info> annotations_of_with_type(info item, info type);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
A \tcode{vector} containing each element \tcode{e} of \tcode{annotations_of(item)}
where
\begin{codeblock}
remove_const(type_of(e)) == remove_const(type)
\end{codeblock}
is \tcode{true}, preserving their order.

\pnum
\throws
\tcode{meta::exception} unless
\begin{itemize}
\item
  the evaluation of
  \tcode{annotations_of(item)} would not exit via an exception and
\item
  \tcode{dealias(type)} represents a type and
  \tcode{is_complete_type(type)} is \tcode{true}.
\end{itemize}
\end{itemdescr}

\rSec2[meta.reflection.extract]{Value extraction}

\pnum
The \tcode{extract} function template may be used
to extract a value out of a reflection when its type is known.

\pnum
The following are defined for exposition only
to aid in the specification of \tcode{extract}.

\begin{itemdecl}
template<class T>
  consteval T @\exposid{extract-ref}@(info r);      // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
\begin{note}
\tcode{T} is a reference type.
\end{note}

\pnum
\returns
If \tcode{r} represents an object $O$,
then a reference to $O$.
Otherwise, a reference to the object declared, or referred to,
by the variable represented by \tcode{r}.

\pnum
\throws
\tcode{meta::exception} unless
\begin{itemize}
\item
  \tcode{r} represents a variable or object of type \tcode{U},
\item
  \tcode{is_convertible_v<remove_reference_t<U>(*)[],\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}
\end{itemdescr}

\begin{itemdecl}
template<class T>
  consteval T @\exposid{extract-member-or-function}@(info r);       // \expos
\end{itemdecl}

\begin{itemdescr}
\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}

\pnum
\throws
\tcode{meta::exception} unless
\begin{itemize}
\item
  \tcode{r} represents a non-static data member with type \tcode{X},
  that is not a bit-field,
  that is a direct member of class \tcode{C},
  \tcode{T} and \tcode{X C::*} are similar types\iref{conv.qual}, and
  \tcode{is_convertible_v<X C::*, T>} is \tcode{true};
\item
  \tcode{r} represents an implicit object member function
  with type \tcode{F} or \tcode{F noexcept}
  that is a direct member of a class \tcode{C},
  and \tcode{T} is \tcode{F C::*}; or
\item
  \tcode{r} represents a non-member function,
  static member function, or
  explicit object member function
  of function type \tcode{F} or \tcode{F noexcept},
  and \tcode{T} is \tcode{F*}.
\end{itemize}
\end{itemdescr}

\begin{itemdecl}
template<class T>
  consteval T @\exposid{extract-value}@(info r);    // \expos
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{U} be the type of the value or object that \tcode{r} represents.

\pnum
\returns
\tcode{static_cast<T>([:$R$:])},
where $R$ is a constant expression of type \tcode{info}
such that \tcode{$R$ == r} is \tcode{true}.

\pnum
\throws
\tcode{meta::exception} unless
\begin{itemize}
\item
  \tcode{U} is a pointer type,
  \tcode{T} and \tcode{U} are either similar\iref{conv.qual}
  or both function pointer types, and
  \tcode{is_convertible_v<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,
  \tcode{remove_extent_t<U>*} and \tcode{T} are similar types, 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}
\end{itemdescr}

\indexlibraryglobal{extract}%
\begin{itemdecl}
template<class T>
  consteval T extract(info r);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{U} be \tcode{remove_cv_t<T>}.

\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (is_reference_type(^^T)) {
  return @\exposid{extract-ref}@<T>(r);
} else if (is_nonstatic_data_member(r) || is_function(r)) {
  return @\exposid{extract-member-or-function}@<U>(r);
} else {
  return @\exposid{extract-value}@<U>(constant_of(r));
}
\end{codeblock}
\end{itemdescr}

\rSec2[meta.reflection.substitute]{Reflection substitution}

\pnum
Let \tcode{\placeholder{TARG-SPLICE}(x)} be:
\begin{itemize}
\item
\tcode{template [: x :]} if \tcode{is_template(x)} is \tcode{true}, otherwise

\item
\tcode{typename [: x :]} if \tcode{is_type(x)} is \tcode{true}, otherwise

\item
\tcode{([: x :])}.
\end{itemize}

\begin{itemdecl}
template<class R>
concept @\deflibconcept{reflection_range}@ =
  ranges::@\libconcept{input_range}@<R> &&
  @\libconcept{same_as}@<ranges::range_value_t<R>, info> &&
  @\libconcept{same_as}@<remove_cvref_t<ranges::range_reference_t<R>>, info>;

template<@\libconcept{reflection_range}@ R = initializer_list<info>>
  consteval bool @\libglobal{can_substitute}@(info templ, R&& arguments);
\end{itemdecl}

\begin{itemdescr}
\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},
in order.

\pnum
\returns
\tcode{true} if \tcode{Z<\placeholder{TARG-SPLICE}(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
\throws
\tcode{meta::exception} unless
\tcode{templ} represents a template,
and every reflection in \tcode{arguments} represents a construct
usable as a template argument\iref{temp.arg}.

\pnum
\begin{note}
If forming \tcode{Z<\placeholder{TARG-SPLICE}(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<info>>
  consteval info substitute(info templ, R&& arguments);
\end{itemdecl}

\begin{itemdescr}
\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},
in order.

\pnum
\returns
\tcode{\reflexpr{Z<\placeholder{TARG-SPLICE}(Args)...>}}.

\pnum
\throws
\tcode{meta::exception} unless
\tcode{can_substitute(templ, arguments)} is \tcode{true}.

\pnum
\begin{note}
If forming \tcode{Z<\placeholder{TARG-SPLICE}(Args)...>} leads to a failure outside of the immediate context,
the program is ill-formed.
\end{note}

\pnum
\begin{example}
\begin{codeblock}
template<class T>
  auto fn1();

static_assert(!can_substitute(^^fn1, {^^int}));
constexpr info r1 = substitute(^^fn1, {^^int});         // error: \tcode{fn1<int>} contains an undeduced
                                                        // placeholder type for its return type

template<class T>
  auto fn2() {
    static_assert(^^T != ^^int);                        // static assertion failed during
                                                        // instantiation of \tcode{fn2<int>}
    return 0;
  }

constexpr bool r2 = can_substitute(^^fn2, {^^int});     // error: instantiation of body of \tcode{fn2<int>}
                                                        // 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<unsigned, 2>}
\end{codeblock}
\end{example}
\end{itemdescr}

\rSec2[meta.reflection.result]{Expression result reflection}

\indexlibraryglobal{reflect_constant}%
\begin{itemdecl}
template<class T>
  consteval info reflect_constant(T expr);
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
\tcode{is_copy_constructible_v<T>} 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
Let \tcode{TCls} be the invented template:
\begin{codeblock}
template<T P> struct TCls;
\end{codeblock}

\pnum
\returns
\tcode{template_arguments_of(\reflexpr{TCls<$V$>})[0]}.
\begin{note}
This is a reflection of an object for class types,
and a reflection of a value otherwise.
\end{note}

\pnum
\throws
\tcode{meta::exception} unless
the \grammarterm{template-id} \tcode{TCls<$V$>} would be valid.

\pnum
\begin{example}
\begin{codeblock}
template<auto D>
  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<N{42}>)[0]);

constexpr info r3 = reflect_constant(K{nullptr});
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<class T>
  consteval info reflect_object(T& expr);
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
\tcode{T} is an object type.

\pnum
\returns
A reflection of the object designated by \tcode{expr}.

\pnum
\throws
\tcode{meta::exception} if
\tcode{E} is not suitable for use as a constant template argument
for a constant template parameter of type \tcode{T\&}\iref{temp.arg.nontype},
where \tcode{E} is an lvalue constant expression that
computes the object that \tcode{expr} refers to.
\end{itemdescr}

\indexlibraryglobal{reflect_function}%
\begin{itemdecl}
template<class T>
  consteval info reflect_function(T& fn);
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
\tcode{T} is a function type.

\pnum
\returns
A reflection of the function designated by \tcode{fn}.

\pnum
\throws
\tcode{meta::exception} if
\tcode{F} is not suitable for use as a constant template argument
for a constant template parameter of type \tcode{T\&}\iref{temp.arg.nontype},
where \tcode{F} is an lvalue constant expression that
computes the function that \tcode{fn} refers to.
\end{itemdescr}

\rSec2[meta.reflection.define.aggregate]{Reflection class definition generation}

\indexlibraryglobal{data_member_options}%
\begin{codeblock}
namespace std::meta {
  struct data_member_options {
    struct @\exposidnc{name-type}@ {                          // \expos
      template<class T>
        requires @\libconcept{constructible_from}@<u8string, T>
        consteval @\exposid{name-type}@(T&&);

      template<class T>
        requires @\libconcept{constructible_from}@<string, T>
        consteval @\exposid{name-type}@(T&&);

    private:
      variant<u8string, string> @\exposidnc{contents}@;       // \expos
    };

    optional<@\exposid{name-type}@> name;
    optional<int> alignment;
    optional<int> bit_width;
    bool no_unique_address = false;
    vector<info> annotations;
  };
}
\end{codeblock}

\pnum
The classes \tcode{data_member_options}
and \tcode{data_member_options::\exposid{name-type}}
are consteval-only types\iref{basic.types.general},
and are not structural types\iref{temp.param}.

\begin{itemdecl}
template<class T>
  requires @\libconcept{constructible_from}@<u8string, T>
  consteval @\exposid{name-type}@(T&& value);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposid{contents}
with \tcode{u8string(std::forward<T>(value))}.
\end{itemdescr}

\begin{itemdecl}
template<class T>
  requires @\libconcept{constructible_from}@<string, T>
  consteval @\exposid{name-type}@(T&& value);
\end{itemdecl}

\begin{itemdescr}
\pnum
\effects
Initializes \exposid{contents}
with \tcode{string(std::forward<T>(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
\returns
A reflection of a data member description
$(T, N, A, W, \mathit{NUA}, \mathit{ANN})$\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 $\bot$ if \tcode{options.name} does not contain a value,
\item
  $A$ is either the alignment value held by \tcode{options.alignment}
  or $\bot$ if \tcode{options.alignment} does not contain a value,
\item
  $W$ is either the value held by \tcode{options.bit_width}
  or $\bot$ if \tcode{options.bit_width} does not contain a value,
\item
  $\mathit{NUA}$ is the value held by \tcode{options.no_unique_address}, and
\item
  $\mathit{ANN}$ is the sequence of values \tcode{constant_of(r)}
  for each \tcode{r} in \tcode{options.annotations}.
\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}

\pnum
\throws
\tcode{meta::exception} unless the following conditions are met:
\begin{itemize}
\item
  \tcode{dealias(type)} represents either an object type or a reference type;
\item
  if \tcode{options.name} contains a value, then:
  \begin{itemize}
  \item
    \tcode{holds_alternative<u8string>(options.name->\exposid{contents})} is \tcode{true}
    and \tcode{get<u8string>(\brk{}options.name->\exposid{contents})}
    contains the spelling of a valid \grammarterm{token}
    that is an \grammarterm{identifier}\iref{lex.name}
    when interpreted with UTF-8, or
  \item
    \tcode{holds_alternative<string>(options.name->\exposid{contents})} is \tcode{true}
    and \tcode{get<string>(opt\-ions.name->\exposid{contents})}
    contains the spelling of a valid \grammarterm{token}
    that is an \grammarterm{identifier}\iref{lex.name}
    when interpreted with the ordinary literal encoding;
  \end{itemize}
  \begin{note}
  Lexical constructs like
  \grammarterm{universal-character-name}s\iref{lex.universal.char} are not processed.
  For example, \tcode{R"(\textbackslash u03B1)"} is an invalid identifier
  and is not interpreted as \tcode{"$\alpha$"}.
  \end{note}
\item
  if \tcode{options.name} does not contain a value,
  then \tcode{options.bit_width} contains a value and
  \tcode{options.annotations} is empty;
\item
  if \tcode{options.bit_width} contains a value $V$, then
  \begin{itemize}
  \item
    \tcode{is_integral_type(type) || is_enum_type(type)} is \tcode{true},
  \item
    \tcode{options.alignment} does not contain a value,
  \item
    \tcode{options.no_unique_address} is \tcode{false},
  \item
    $V$ is not negative, and
  \item
    if $V$ equals \tcode{0},
    then \tcode{options.name} does not contain a value; and
  \item
    if \tcode{options.name} does not contain a value, then
    \tcode{is_const(type) || is_volatile(type)} is \tcode{false}; 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)}; and
  \item
    for every reflection \tcode{r} in \tcode{options.annotations},
    \tcode{\exposid{has-type}(r)} is \tcode{true},
    \tcode{type_of(r)} represents a non-array object type, and
    evaluation of \tcode{constant_of(r)} does not exit via an exception.
\end{itemize}
\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<info>>
  consteval info define_aggregate(info class_type, R&& mdescrs);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let $C$ be the type 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, \mathit{ANN}_K)$ be
the corresponding data member description represented by $r_K$.

\pnum
\constantwhen
\begin{itemize}
\item
  \tcode{class_type} represents a cv-unqualified class type;
\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 $\bot$ and $N_L$ is not $\bot$,
  then either:
  \begin{itemize}
  \item
    $N_K$ is not the same identifier as $N_L$ or
  \item
    $N_K$ is the identifier \tcode{_} (\ucode{005f} low line).
    \begin{note}
    Every provided identifier is unique or \tcode{"_"}.
    \end{note}
  \end{itemize}
\end{itemize}

\pnum
\effects
Produces an injected declaration $D$\iref{expr.const.reflect}
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.reflect}
  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$
  with public access
  belonging to the class scope of $D$
  with the following properties:
  \begin{itemize}
  \item
    If $N_K$ is $\bot$,
    $M_K$ is an unnamed bit-field.
    Otherwise, $M_K$ is a non-static data member whose name is the identifier
    $N_K$.
  \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 $\bot$,
    $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 $\bot$,
    $M_K$ has the \grammarterm{alignment-specifier} \tcode{alignas($A_K$)}.
    Otherwise, $M_K$ has no \grammarterm{alignment-specifier}.
  \item
    For every reflection \tcode{r} in $\mathit{ANN}_K$,
    $M_K$ has an annotation
    whose underlying constant\iref{dcl.attr.annotation} is \tcode{r}.
  \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}.

\pnum
\remarks
If $C$ is a specialization of a templated class and
it has not been instantiated,
$C$ is treated as an explicit specialization.
\end{itemdescr}

\rSec2[meta.reflection.traits]{Reflection type traits}

\pnum
This subclause specifies \tcode{consteval} functions to
query the properties of types\iref{meta.unary},
query the relationships between types\iref{meta.rel}, or
transform types\iref{meta.trans},
during program translation.
Each \tcode{consteval} function declared in this class
has an associated class template declared elsewhere in this document.

\pnum
Every function and function template declared in this subclause
throws an exception of type \tcode{meta::exception}
unless the following conditions are met:
\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_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_structural_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<info>>
  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 type1, info type2);
consteval bool @\libglobal{is_swappable_type}@(info type);

consteval bool @\libglobal{is_destructible_type}@(info type);

template<@\libconcept{reflection_range}@ R = initializer_list<info>>
  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<info>>
  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 type1, info type2);
consteval bool @\libglobal{is_nothrow_swappable_type}@(info type);

consteval bool @\libglobal{is_nothrow_destructible_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<info>>
  consteval bool @\libglobal{is_invocable_type}@(info type, R&& type_args);
template<@\libconcept{reflection_range}@ R = initializer_list<info>>
  consteval bool @\libglobal{is_invocable_r_type}@(info type_result, info type, R&& type_args);

template<@\libconcept{reflection_range}@ R = initializer_list<info>>
  consteval bool @\libglobal{is_nothrow_invocable_type}@(info type, R&& type_args);
template<@\libconcept{reflection_range}@ R = initializer_list<info>>
  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<info>>
  consteval info @\libglobal{common_type}@(R&& type_args);
template<@\libconcept{reflection_range}@ R = initializer_list<info>>
  consteval info @\libglobal{common_reference}@(R&& type_args);
consteval info @\libglobal{underlying_type}@(info type);
template<@\libconcept{reflection_range}@ R = initializer_list<info>>
  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
For a function or function template $F$ defined in this subclause,
let $C$ be its associated class template.
For the evaluation of a call to $F$,
let $S$ be the specialization of $C$ in terms of which the call is specified.
\begin{itemize}
\item
  If
  \begin{itemize}
  \item
    the template arguments of $S$ violate a condition specified
    in a \Fundescx{Mandates} element in the specification of $C$;
  \item
    the call is specified to produce a reflection of a type,
    but $S$ would have no member named \tcode{type}; or
  \item
    the call is specified to return \tcode{$S$::value},
    but that expression would not be a valid converted constant expression of type \tcode{R},
    where \tcode{R} is the return type of $F$;
  \end{itemize}
  then an exception of type \tcode{meta::exception} is thrown.
  \begin{note}
  For the first case, $S$ is not instantiated.
  \end{note}
  \item
    Otherwise, if the instantiation of $S$ would result in undefined behavior
    due to dependence on an incomplete type\iref{meta.rqmts},
    then the call is not a constant subexpression.
  \item
    Otherwise, if the template arguments of $S$ do not meet the preconditions of $C$,
    then it is unspecified whether the call is a constant subexpression.
    If it is, the call produces the result
    that would be produced if $C$ had no preconditions.
\end{itemize}

\pnum
Each 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}

\begin{libreqtab2b}{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

\tcode{bool meta::\placeholder{UNARY}(info type);\br
bool meta::\placeholder{UNARY}_type(info type);}  &
\tcode{std::\placeholder{UNARY}<$T$>::value},
where $T$ is the type or type alias represented by \tcode{type}
\\  \rowsep

\tcode{bool meta::\placeholder{BINARY}(info t1, info t2);\br
bool meta::\placeholder{BINARY}_type(info t1, info t2);}  &
\tcode{std::\placeholder{BINARY}<$T_1$, $T_2$>::value},
where $T_1$ and $T_2$ are the types or type aliases
represented by \tcode{t1} and \tcode{t2}, respectively
\\  \rowsep

\tcode{template<reflection_range R>\br
  bool meta::\placeholder{VARIADIC}_type(info type, R\&\& args);}  &
\tcode{std::\placeholder{VARIADIC}<$T$, $U$...>::value},
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<reflection_range R>\br
  bool meta::\placeholder{VARIADIC}_type(info t1, info t2, R\&\& args);}  &
\tcode{std::\placeholder{VARIADIC}<$T_1$, $T_2$, $U$...>::value},
where $T_1$ and $T_2$ 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);}  &
A reflection representing the type denoted by
\tcode{std::\placeholder{UNARY}<\brk{}$T$>::type},
where $T$ is the type or type alias represented by \tcode{type}
\\  \rowsep

\tcode{template<reflection_range R>\br
  info meta::\placeholder{VARIADIC}(R\&\& args);}  &
A reflection representing the type denoted by
\tcode{std::\placeholder{VARIADIC}<$T$...>::type},
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<reflection_range R>\br
  info meta::\placeholder{VARIADIC}(info type, R\&\& args);}  &
A reflection representing the type denoted by
\tcode{std::\placeholder{VARIADIC}<$T$, $U$...>::type},
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{libreqtab2b}

\pnum
\begin{note}
For those functions or function templates which return a reflection,
that reflection always represents a type and never a type alias.
\end{note}

\pnum
\begin{note}
If \tcode{t} is a reflection of the type \tcode{int}
and \tcode{u} is a reflection of an alias to the type \tcode{int},
then \tcode{t == u} is \tcode{false}
but \tcode{is_same_type(t, u)} is \tcode{true}.
Also, \tcode{t == dealias(u)} is \tcode{true}.
\end{note}

\indexlibraryglobal{rank}%
\begin{itemdecl}
consteval size_t rank(info type);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{std::rank<$T$>::value},
where $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{std::extent<$T$, $I$>::value},
where $T$ is the type represented by \tcode{dealias(type)}
and $I$ is a constant equal to \tcode{i}.
\end{itemdescr}

\indexlibraryglobal{tuple_size}%
\begin{itemdecl}
consteval size_t tuple_size(info type);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{std::tuple_size<$T$>::value},
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{std::tuple_element<$I$, $T$>::type},
where $T$ is the type represented by \tcode{dealias(type)}
and $I$ is a constant equal to \tcode{index}.
\end{itemdescr}

\indexlibraryglobal{variant_size}%
\begin{itemdecl}
consteval size_t variant_size(info type);
\end{itemdecl}

\begin{itemdescr}
\pnum
\returns
\tcode{std::variant_size<$T$>::value},
where $T$ is the type represented by \tcode{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{std::variant_alternative<$I$, $T$>::type},
where $T$ is the type represented by \tcode{dealias(type)}
and $I$ is a constant 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{std::type_order<$T_1$, $T_2$>::value},
where $T_1$ and $T_2$ are the types
represented by \tcode{de\-alias(\brk{}t1)} and \tcode{dealias(t2)}, respectively.
\end{itemdescr}

\rSec1[ratio]{Compile-time rational arithmetic}

\rSec2[ratio.general]{General}

\pnum
\indexlibraryglobal{ratio}%
Subclause~\ref{ratio} describes the ratio library. It provides a class template
\tcode{ratio} which exactly represents any finite rational number with a
numerator and denominator representable by compile-time constants of type
\tcode{intmax_t}.

\pnum
Throughout subclause~\ref{ratio}, the names of template parameters are used to express
type requirements. If a template parameter is named \tcode{R1} or \tcode{R2},
and the template argument is not a specialization of the \tcode{ratio} template,
the program is ill-formed.

\rSec2[ratio.syn]{Header \tcode{<ratio>} synopsis}

\indexheader{ratio}%
\begin{codeblockdigitsep}
// all freestanding
namespace std {
  // \ref{ratio.ratio}, class template \tcode{ratio}
  template<intmax_t N, intmax_t D = 1> class ratio;

  // \ref{ratio.arithmetic}, ratio arithmetic
  template<class R1, class R2> using ratio_add = @\seebelow@;
  template<class R1, class R2> using ratio_subtract = @\seebelow@;
  template<class R1, class R2> using ratio_multiply = @\seebelow@;
  template<class R1, class R2> using ratio_divide = @\seebelow@;

  // \ref{ratio.comparison}, ratio comparison
  template<class R1, class R2> struct ratio_equal;
  template<class R1, class R2> struct ratio_not_equal;
  template<class R1, class R2> struct ratio_less;
  template<class R1, class R2> struct ratio_less_equal;
  template<class R1, class R2> struct ratio_greater;
  template<class R1, class R2> struct ratio_greater_equal;

  template<class R1, class R2>
    constexpr bool @\libglobal{ratio_equal_v}@ = ratio_equal<R1, R2>::value;
  template<class R1, class R2>
    constexpr bool @\libglobal{ratio_not_equal_v}@ = ratio_not_equal<R1, R2>::value;
  template<class R1, class R2>
    constexpr bool @\libglobal{ratio_less_v}@ = ratio_less<R1, R2>::value;
  template<class R1, class R2>
    constexpr bool @\libglobal{ratio_less_equal_v}@ = ratio_less_equal<R1, R2>::value;
  template<class R1, class R2>
    constexpr bool @\libglobal{ratio_greater_v}@ = ratio_greater<R1, R2>::value;
  template<class R1, class R2>
    constexpr bool @\libglobal{ratio_greater_equal_v}@ = ratio_greater_equal<R1, R2>::value;

  // \ref{ratio.si}, convenience SI typedefs
  using @\libglobal{quecto}@ = ratio<1, 1'000'000'000'000'000'000'000'000'000'000>;     // \seebelow
  using @\libglobal{ronto}@  = ratio<1,     1'000'000'000'000'000'000'000'000'000>;     // \seebelow
  using @\libglobal{yocto}@  = ratio<1,         1'000'000'000'000'000'000'000'000>;     // \seebelow
  using @\libglobal{zepto}@  = ratio<1,             1'000'000'000'000'000'000'000>;     // \seebelow
  using @\libglobal{atto}@   = ratio<1,                 1'000'000'000'000'000'000>;
  using @\libglobal{femto}@  = ratio<1,                     1'000'000'000'000'000>;
  using @\libglobal{pico}@   = ratio<1,                         1'000'000'000'000>;
  using @\libglobal{nano}@   = ratio<1,                             1'000'000'000>;
  using @\libglobal{micro}@  = ratio<1,                                 1'000'000>;
  using @\libglobal{milli}@  = ratio<1,                                     1'000>;
  using @\libglobal{centi}@  = ratio<1,                                       100>;
  using @\libglobal{deci}@   = ratio<1,                                        10>;
  using @\libglobal{deca}@   = ratio<                                       10, 1>;
  using @\libglobal{hecto}@  = ratio<                                      100, 1>;
  using @\libglobal{kilo}@   = ratio<                                    1'000, 1>;
  using @\libglobal{mega}@   = ratio<                                1'000'000, 1>;
  using @\libglobal{giga}@   = ratio<                            1'000'000'000, 1>;
  using @\libglobal{tera}@   = ratio<                        1'000'000'000'000, 1>;
  using @\libglobal{peta}@   = ratio<                    1'000'000'000'000'000, 1>;
  using @\libglobal{exa}@    = ratio<                1'000'000'000'000'000'000, 1>;
  using @\libglobal{zetta}@  = ratio<            1'000'000'000'000'000'000'000, 1>;     // \seebelow
  using @\libglobal{yotta}@  = ratio<        1'000'000'000'000'000'000'000'000, 1>;     // \seebelow
  using @\libglobal{ronna}@  = ratio<    1'000'000'000'000'000'000'000'000'000, 1>;     // \seebelow
  using @\libglobal{quetta}@ = ratio<1'000'000'000'000'000'000'000'000'000'000, 1>;     // \seebelow
}
\end{codeblockdigitsep}

\rSec2[ratio.ratio]{Class template \tcode{ratio}}

\indexlibraryglobal{ratio}%
\begin{codeblock}
namespace std {
  template<intmax_t N, intmax_t D = 1> class ratio {
  public:
    static constexpr intmax_t num;
    static constexpr intmax_t den;
    using type = ratio<num, den>;
  };
}
\end{codeblock}

\pnum
\indextext{signed integer representation!two's complement}%
If the template argument \tcode{D} is zero or the absolute values of either of the
template arguments \tcode{N} and \tcode{D} is not representable by type
\tcode{intmax_t}, the program is ill-formed.
\begin{note}
These rules ensure that infinite
ratios are avoided and that for any negative input, there exists a representable value
of its absolute value which is positive.
This excludes the most negative value.
\end{note}

\pnum
The static data members \tcode{num} and \tcode{den} shall have the following values,
where \tcode{gcd} represents the greatest common divisor of the absolute values of
\tcode{N} and \tcode{D}:

\begin{itemize}
\item \tcode{num} shall have the value \tcode{$\operatorname{sgn}(\tcode{N})$ * $\operatorname{sgn}(\tcode{D})$ * abs(N) / gcd}.
\item \tcode{den} shall have the value \tcode{abs(D) / gcd}.
\end{itemize}

\rSec2[ratio.arithmetic]{Arithmetic on \tcode{ratio}{s}}

\pnum
\indexlibraryglobal{ratio_add}%
\indexlibraryglobal{ratio_subtract}%
\indexlibraryglobal{ratio_multiply}%
\indexlibraryglobal{ratio_divide}%
Each of the alias templates \tcode{ratio_add}, \tcode{ratio_subtract}, \tcode{ratio_multiply},
and \tcode{ratio_divide} denotes the result of an arithmetic computation on two
\tcode{ratio}{s} \tcode{R1} and \tcode{R2}. With \tcode{X} and \tcode{Y} computed (in the
absence of arithmetic overflow) as specified by \tref{ratio.arithmetic}, each alias
denotes a \tcode{ratio<U, V>} such that \tcode{U} is the same as \tcode{ratio<X, Y>::num} and
\tcode{V} is the same as \tcode{ratio<X, Y>::den}.

\pnum
If it is not possible to represent \tcode{U} or \tcode{V} with \tcode{intmax_t}, the program is
ill-formed. Otherwise, an implementation should yield correct values of \tcode{U} and
\tcode{V}. If it is not possible to represent \tcode{X} or \tcode{Y} with \tcode{intmax_t}, the
program is ill-formed unless the implementation yields correct values of \tcode{U} and
\tcode{V}.

\begin{floattable}{Expressions used to perform ratio arithmetic}{ratio.arithmetic}
{lll}
\topline
\lhdr{Type}                     &
  \chdr{Value of \tcode{X}}     &
  \rhdr{Value of \tcode{Y}}     \\ \rowsep

\tcode{ratio_add<R1, R2>}       &
  \tcode{R1::num * R2::den +}   &
  \tcode{R1::den * R2::den}     \\
                                &
  \tcode{R2::num * R1::den}     &
                                \\ \rowsep

\tcode{ratio_subtract<R1, R2>}  &
  \tcode{R1::num * R2::den -}   &
  \tcode{R1::den * R2::den}     \\
                                &
  \tcode{R2::num * R1::den}     &
                                \\ \rowsep

\tcode{ratio_multiply<R1, R2>}  &
  \tcode{R1::num * R2::num}     &
  \tcode{R1::den * R2::den}     \\ \rowsep

\tcode{ratio_divide<R1, R2>}    &
  \tcode{R1::num * R2::den}     &
  \tcode{R1::den * R2::num}     \\
\end{floattable}

\pnum
\begin{example}
\begin{codeblock}
static_assert(ratio_add<ratio<1, 3>, ratio<1, 6>>::num == 1, "1/3+1/6 == 1/2");
static_assert(ratio_add<ratio<1, 3>, ratio<1, 6>>::den == 2, "1/3+1/6 == 1/2");
static_assert(ratio_multiply<ratio<1, 3>, ratio<3, 2>>::num == 1, "1/3*3/2 == 1/2");
static_assert(ratio_multiply<ratio<1, 3>, ratio<3, 2>>::den == 2, "1/3*3/2 == 1/2");

// The following cases may cause the program to be ill-formed under some implementations
static_assert(ratio_add<ratio<1, INT_MAX>, ratio<1, INT_MAX>>::num == 2,
  "1/MAX+1/MAX == 2/MAX");
static_assert(ratio_add<ratio<1, INT_MAX>, ratio<1, INT_MAX>>::den == INT_MAX,
  "1/MAX+1/MAX == 2/MAX");
static_assert(ratio_multiply<ratio<1, INT_MAX>, ratio<INT_MAX, 2>>::num == 1,
  "1/MAX * MAX/2 == 1/2");
static_assert(ratio_multiply<ratio<1, INT_MAX>, ratio<INT_MAX, 2>>::den == 2,
  "1/MAX * MAX/2 == 1/2");
\end{codeblock}

\end{example}

\rSec2[ratio.comparison]{Comparison of \tcode{ratio}{s}}

\indexlibraryglobal{ratio_equal}%
\begin{itemdecl}
template<class R1, class R2>
  struct ratio_equal : bool_constant<R1::num == R2::num && R1::den == R2::den> { };
\end{itemdecl}

\indexlibraryglobal{ratio_not_equal}%
\begin{itemdecl}
template<class R1, class R2>
  struct ratio_not_equal : bool_constant<!ratio_equal_v<R1, R2>> { };
\end{itemdecl}

\indexlibraryglobal{ratio_less}%
\begin{itemdecl}
template<class R1, class R2>
  struct ratio_less : bool_constant<@\seebelow@> { };
\end{itemdecl}

\begin{itemdescr}
\pnum
If \tcode{R1::num} $\times$ \tcode{R2::den} is less than \tcode{R2::num} $\times$ \tcode{R1::den},
\tcode{ratio_less<R1, R2>} shall be
derived from \tcode{bool_constant<true>}; otherwise it shall be derived from
\tcode{bool_constant<false>}. Implementations may use other algorithms to
compute this relationship to avoid overflow. If overflow occurs, the program is ill-formed.
\end{itemdescr}

\indexlibraryglobal{ratio_less_equal}%
\begin{itemdecl}
template<class R1, class R2>
  struct ratio_less_equal : bool_constant<!ratio_less_v<R2, R1>> { };
\end{itemdecl}

\indexlibraryglobal{ratio_greater}%
\begin{itemdecl}
template<class R1, class R2>
  struct ratio_greater : bool_constant<ratio_less_v<R2, R1>> { };
\end{itemdecl}

\indexlibraryglobal{ratio_greater_equal}%
\begin{itemdecl}
template<class R1, class R2>
  struct ratio_greater_equal : bool_constant<!ratio_less_v<R1, R2>> { };
\end{itemdecl}

\rSec2[ratio.si]{SI types for \tcode{ratio}}

\pnum
\indexlibraryglobal{quecto}%
\indexlibraryglobal{ronto}%
\indexlibraryglobal{yocto}%
\indexlibraryglobal{zepto}%
\indexlibraryglobal{zetta}%
\indexlibraryglobal{yotta}%
\indexlibraryglobal{ronna}%
\indexlibraryglobal{quetta}%
For each of the \grammarterm{typedef-name}{s}
\tcode{quecto}, \tcode{ronto},
\tcode{yocto}, \tcode{zepto},
\tcode{zetta}, \tcode{yotta},
\tcode{ronna}, and \tcode{quetta},
if both of the constants used in its
specification are representable by \tcode{intmax_t}, the typedef is
declared; if either of the constants is not representable by \tcode{intmax_t},
the typedef is not declared.
