Skip to content

P0466R5 Layout-compatibility and Pointer-interconvertibility Traits #3065

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 6, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions source/utilities.tex
Original file line number Diff line number Diff line change
Expand Up @@ -16275,7 +16275,9 @@
\rSec2[meta.type.synop]{Header \tcode{<type_traits>} 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.
Expand Down Expand Up @@ -16385,6 +16387,8 @@
template<class Base, class Derived> struct is_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;
Expand Down Expand Up @@ -16666,6 +16670,11 @@
inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
template<class From, class To>
inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<From, To>::value;
template<class T, class U>
inline constexpr bool is_layout_compatible_v = is_layout_compatible<T, U>::value;
template<class Base, class Derived>
inline constexpr bool is_pointer_interconvertible_base_of_v
= is_pointer_interconvertible_base_of<Base, Derived>::value;
template<class Fn, class... ArgTypes>
inline constexpr bool is_invocable_v = is_invocable<Fn, ArgTypes...>::value;
template<class R, class Fn, class... ArgTypes>
Expand All @@ -16684,6 +16693,12 @@
template<class B>
inline constexpr bool 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;
}
Expand Down Expand Up @@ -17498,6 +17513,29 @@
types, arrays of unknown
bound, or \cv{}~\tcode{void} types. \\ \rowsep

\indexlibrary{\idxcode{is_layout_compatible}}%
\tcode{template<class T, class U>}\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<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

\indexlibrary{\idxcode{is_invocable}}%
\tcode{template<class Fn, class... ArgTypes>}\br
\tcode{struct is_invocable;} &
Expand Down Expand Up @@ -18315,6 +18353,75 @@
is a \oldconcept{UnaryTypeTrait} with a base characteristic of \tcode{bool_constant<!bool(B::\brk{}value)>}.
\end{itemdescr}

\rSec2[meta.member]{Member relationships}

\indexlibrary{\idxcode{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}

\indexlibrary{\idxcode{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 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>( &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, C>( &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;
Expand Down