Skip to content

Commit 8cd5ba7

Browse files
committed
P0466R5 Layout-compatibility and Pointer-interconvertibility Traits
Fixes #3035 Editorial changes: - Adjusted parenthesis in is_layout_compatible requirements. - Adjusted requirements in tables to use "shall". - Moved punctuation outside quote marks in comments in example. - Declared variable templates at the appropriate place in synopsis.
1 parent 67db942 commit 8cd5ba7

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

source/support.tex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,12 @@
622622
\tcode{<type_traits>} \\ \rowsep
623623
\defnlibxname{cpp_lib_is_invocable} & \tcode{201703L} &
624624
\tcode{<type_traits>} \\ \rowsep
625+
\defnlibxname{cpp_lib_is_layout_compatible} & \tcode{201907L} &
626+
\tcode{<type_traits>} \\ \rowsep
625627
\defnlibxname{cpp_lib_is_null_pointer} & \tcode{201309L} &
626628
\tcode{<type_traits>} \\ \rowsep
629+
\defnlibxname{cpp_lib_is_pointer_interconvertible} & \tcode{201907L} &
630+
\tcode{<type_traits>} \\ \rowsep
627631
\defnlibxname{cpp_lib_is_swappable} & \tcode{201603L} &
628632
\tcode{<type_traits>} \\ \rowsep
629633
\defnlibxname{cpp_lib_launder} & \tcode{201606L} &

source/utilities.tex

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16519,6 +16519,8 @@
1651916519
template<class Base, class Derived> struct is_base_of;
1652016520
template<class From, class To> struct is_convertible;
1652116521
template<class From, class To> struct is_nothrow_convertible;
16522+
template<class T, class U> struct is_layout_compatible;
16523+
template<class Base, class Derived> struct is_pointer_interconvertible_base_of;
1652216524

1652316525
template<class Fn, class... ArgTypes> struct is_invocable;
1652416526
template<class R, class Fn, class... ArgTypes> struct is_invocable_r;
@@ -16803,6 +16805,11 @@
1680316805
inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
1680416806
template<class From, class To>
1680516807
inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<From, To>::value;
16808+
template<class T, class U>
16809+
inline constexpr bool is_layout_compatible_v = is_layout_compatible<T, U>::value;
16810+
template<class Base, class Derived>
16811+
inline constexpr bool is_pointer_interconvertible_base_of_v
16812+
= is_pointer_interconvertible_base_of<Base, Derived>::value;
1680616813
template<class Fn, class... ArgTypes>
1680716814
inline constexpr bool is_invocable_v = is_invocable<Fn, ArgTypes...>::value;
1680816815
template<class R, class Fn, class... ArgTypes>
@@ -16821,6 +16828,14 @@
1682116828
template<class B>
1682216829
inline constexpr bool negation_v = negation<B>::value;
1682316830

16831+
// \ref{meta.member}, member relationships
16832+
template<class S, class M>
16833+
constexpr bool
16834+
is_pointer_interconvertible_with_class(M S::*m) noexcept;
16835+
template<class S1, class S2, class M1, class M2>
16836+
constexpr bool
16837+
is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept;
16838+
1682416839
// \ref{meta.const.eval}, constant evaluation context
1682516840
constexpr bool is_constant_evaluated() noexcept;
1682616841
}
@@ -17627,6 +17642,29 @@
1762717642
types, arrays of unknown
1762817643
bound, or \cv{}~\tcode{void} types. \\ \rowsep
1762917644

17645+
\indexlibrary{\idxcode{is_layout_compatible}}%
17646+
\tcode{template<class T, class U>}\br
17647+
\tcode{struct is_layout_compatible;} &
17648+
\tcode{T} and \tcode{U} are layout-compatible\iref{basic.types} &
17649+
\tcode{T} and \tcode{U} shall be complete types,
17650+
\cv{}~\tcode{void},
17651+
or arrays of unknown bound. \\ \rowsep
17652+
17653+
\indexlibrary{\idxcode{is_pointer_interconvertible_base_of}}%
17654+
\tcode{template<class Base, class Derived>}\br
17655+
\tcode{struct is_pointer_interconvertible_base_of;} &
17656+
\tcode{Derived} is unambiguously derived from \tcode{Base}
17657+
without regard to \cv{}-qualifiers,
17658+
and each object of type \tcode{Derived}
17659+
is pointer-interconvertible\iref{basic.compound} with
17660+
its \tcode{Base} subobject,
17661+
or \tcode{Base} and \tcode{Derived} are not unions
17662+
and name the same class type
17663+
without regard to \cv{}-qualifiers. &
17664+
If \tcode{Base} and \tcode{Derived} are non-union class types
17665+
and are not (possibly \cv{}-qualified versions of) the same type,
17666+
\tcode{Derived} shall be a complete type. \\ \rowsep
17667+
1763017668
\indexlibrary{\idxcode{is_invocable}}%
1763117669
\tcode{template<class Fn, class... ArgTypes>}\br
1763217670
\tcode{struct is_invocable;} &
@@ -18440,6 +18478,76 @@
1844018478
is a \oldconcept{UnaryTypeTrait} with a base characteristic of \tcode{bool_constant<!bool(B::\brk{}value)>}.
1844118479
\end{itemdescr}
1844218480

18481+
\rSec2[meta.member]{Member relationships}
18482+
18483+
\indexlibrary{\idxcode{is_pointer_interconvertible_with_class}}
18484+
\begin{itemdecl}
18485+
template<class S, class M>
18486+
constexpr bool
18487+
is_pointer_interconvertible_with_class(M S::*m) noexcept;
18488+
\end{itemdecl}
18489+
18490+
\begin{itemdescr}
18491+
\pnum
18492+
\mandates \tcode{S} is a complete type.
18493+
18494+
\pnum
18495+
\returns \tcode{true} if and only if
18496+
\tcode{S} is a standard-layout type,
18497+
\tcode{M} is an object type,
18498+
\tcode{m} is not null,
18499+
and each object \tcode{s} of type \tcode{S}
18500+
is pointer-interconvertible\iref{basic.compound}
18501+
with its subobject \tcode{s.*m}.
18502+
\end{itemdescr}
18503+
18504+
\indexlibrary{\idxcode{is_corresponding_member}}
18505+
\begin{itemdecl}
18506+
template<class S1, class S2, class M1, class M2>
18507+
constexpr bool
18508+
is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept;
18509+
\end{itemdecl}
18510+
18511+
\begin{itemdescr}
18512+
\pnum
18513+
\mandates \tcode{S1} and \tcode{S2} are complete types.
18514+
18515+
\pnum
18516+
\returns \tcode{true} if and only if
18517+
\tcode{S1} and \tcode{S2} are standard-layout types,
18518+
\tcode{M1} and \tcode{M2} are object types,
18519+
\tcode{m1} and \tcode{m2} are not null,
18520+
and \tcode{m1} and \tcode{m2} point to corresponding members of
18521+
the common initial sequence\iref{class.mem} of \tcode{S1} and \tcode{S2}
18522+
\end{itemdescr}
18523+
18524+
\pnum
18525+
\begin{note}
18526+
The type of a pointer-to-member expression \tcode{\&C::b}
18527+
is not always a pointer to member of \tcode{C},
18528+
leading to potentially surprising results
18529+
when using these functions in conjunction with inheritance.
18530+
Consider the following example:
18531+
\begin{codeblock}
18532+
struct A { int a; }; // a standard-layout class
18533+
struct B { int b; }; // a standard-layout class
18534+
struct C: public A, public B { }; // not a standard-layout class
18535+
18536+
static_assert( is_pointer_interconvertible_with_class( &C::b ) );
18537+
// Succeeds because, despite its appearance, \tcode{\&C::b} has type
18538+
// "pointer to member of \tcode{B} of type \tcode{int}".
18539+
static_assert( is_pointer_interconvertible_with_class<C>( &C::b ) );
18540+
// Forces the use of class \tcode{C}, and fails.
18541+
18542+
static_assert( is_corresponding_member( &C::a, &C::b ) );
18543+
// Succeeds because, despite its appearance, \tcode{\&C::a} and \tcode{\&C::b} have types
18544+
// "pointer to member of \tcode{A} of type \tcode{int}" and
18545+
// "pointer to member of \tcode{B} of type \tcode{int}", respectively.
18546+
static_assert( is_corresponding_member<C, C>( &C::a, &C::b ) );
18547+
// Forces the use of class \tcode{C}, and fails.
18548+
\end{codeblock}
18549+
\end{note}
18550+
1844318551
\rSec2[meta.endian]{Endian}
1844418552

1844518553
\pnum

0 commit comments

Comments
 (0)