From b83cb6d961ef1594215d015cb2e26258f99b57f5 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 23 Jul 2019 13:09:13 +0100 Subject: [PATCH] P0466R5 Layout-compatibility and Pointer-interconvertibility Traits Feature test macros were already (accidentally) added as part of P0660R10. --- source/utilities.tex | 107 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/source/utilities.tex b/source/utilities.tex index 757a59ee69..ab39c0a254 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -16275,7 +16275,9 @@ \rSec2[meta.type.synop]{Header \tcode{} synopsis} \indexhdr{type_traits}% +\indexlibrary{\idxcode{is_layout_compatible_v}}% \indexlibrary{\idxcode{is_nothrow_convertible_v}}% +\indexlibrary{\idxcode{is_pointer_interconvertible_base_of_v}}% \indexlibrary{\idxcode{type_identity_t}}% \indexlibrary{\idxcode{common_reference_t}}% % FIXME: Many index entries missing. @@ -16385,6 +16387,8 @@ template struct is_base_of; template struct is_convertible; template struct is_nothrow_convertible; + template struct is_layout_compatible; + template struct is_pointer_interconvertible_base_of; template struct is_invocable; template struct is_invocable_r; @@ -16666,6 +16670,11 @@ inline constexpr bool is_convertible_v = is_convertible::value; template inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible::value; + template + inline constexpr bool is_layout_compatible_v = is_layout_compatible::value; + template + inline constexpr bool is_pointer_interconvertible_base_of_v + = is_pointer_interconvertible_base_of::value; template inline constexpr bool is_invocable_v = is_invocable::value; template @@ -16684,6 +16693,12 @@ template inline constexpr bool negation_v = negation::value; + // \ref{meta.member}, member relationships + template + constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept; + template + 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; } @@ -17498,6 +17513,29 @@ types, arrays of unknown bound, or \cv{}~\tcode{void} types. \\ \rowsep +\indexlibrary{\idxcode{is_layout_compatible}}% +\tcode{template}\br + \tcode{struct is_layout_compatible;} & + \tcode{T} and \tcode{U} are layout-compatible\iref{basic.types} & + \tcode{T} and \tcode{U} shall be complete types, + \cv{}~\tcode{void}, + or arrays of unknown bound. \\ \rowsep + +\indexlibrary{\idxcode{is_pointer_interconvertible_base_of}}% +\tcode{template}\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 + \indexlibrary{\idxcode{is_invocable}}% \tcode{template}\br \tcode{struct is_invocable;} & @@ -18315,6 +18353,75 @@ is a \oldconcept{UnaryTypeTrait} with a base characteristic of \tcode{bool_constant}. \end{itemdescr} +\rSec2[meta.member]{Member relationships} + +\indexlibrary{\idxcode{is_pointer_interconvertible_with_class}} +\begin{itemdecl} +template + 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} + +\indexlibrary{\idxcode{is_corresponding_member}} +\begin{itemdecl} +template + 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 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::b ) ); + // Forces the use of class \tcode{C}, and fails. + +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::a, &C::b ) ); + // Forces the use of class \tcode{C}, and fails. +\end{codeblock} +\end{example} +\end{note} + \rSec2[meta.const.eval]{Constant evaluation context} \begin{itemdecl} constexpr bool is_constant_evaluated() noexcept;