Skip to content

P2255R2 A type trait to detect reference binding to temporary #5283

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
Feb 20, 2022
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions source/support.tex
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,7 @@
#define @\defnlibxname{cpp_lib_ranges_to_container}@ 202202L // also in \libheader{ranges}
#define @\defnlibxname{cpp_lib_ranges_zip}@ 202110L // also in \libheader{ranges}, \libheader{tuple}, \libheader{utility}
#define @\defnlibxname{cpp_lib_raw_memory_algorithms}@ 201606L // also in \libheader{memory}
#define @\defnlibxname{cpp_lib_reference_from_temporary}@ 202202L // also in \libheader{type_traits}
#define @\defnlibxname{cpp_lib_remove_cvref}@ 201711L // also in \libheader{type_traits}
#define @\defnlibxname{cpp_lib_result_of_sfinae}@ 201210L // also in \libheader{functional}, \libheader{type_traits}
#define @\defnlibxname{cpp_lib_robust_nonmodifying_seq_ops}@ 201304L // also in \libheader{algorithm}
Expand Down
90 changes: 90 additions & 0 deletions source/utilities.tex
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,11 @@
\begin{codeblock}
!is_convertible_v<U1, T1> || !is_convertible_v<U2, T2>
\end{codeblock}
This constructor is defined as deleted if
\tcode{reference_constructs_from_temporary_v<first_type, U1\&\&>}
is \tcode{true} or
\tcode{reference_constructs_from_temporary_v<second_type, U2\&\&>}
is \tcode{true}.
\end{itemdescr}

\indexlibraryctor{pair}%
Expand Down Expand Up @@ -909,6 +914,12 @@
!is_convertible_v<decltype(get<0>(@\exposid{FWD}@(p))), T1> ||
!is_convertible_v<decltype(get<1>(@\exposid{FWD}@(p))), T2>
\end{codeblock}
The constructor is defined as deleted if
\begin{codeblock}
reference_constructs_from_temporary_v<first_type, decltype(get<0>(@\exposid{FWD}@(p)))> ||
reference_constructs_from_temporary_v<second_type, decltype(get<1>(@\exposid{FWD}@(p)))>
\end{codeblock}
is \tcode{true}.
\end{itemdescr}

\indexlibraryctor{pair}%
Expand Down Expand Up @@ -936,6 +947,11 @@
\tcode{std::forward<U>(x)}.) This form of construction, whereby constructor
arguments for \tcode{first} and \tcode{second} are each provided in a separate
\tcode{tuple} object, is called \defn{piecewise construction}.
\begin{note}
If a data member of \tcode{pair} is of reference type and
its initialization binds it to a temporary object,
the program is ill-formed\iref{class.base.init}.
\end{note}
\end{itemdescr}

\indexlibrarymember{operator=}{pair}%
Expand Down Expand Up @@ -1731,6 +1747,11 @@
\begin{codeblock}
!conjunction_v<is_convertible<UTypes, Types>...>
\end{codeblock}
This constructor is defined as deleted if
\begin{codeblock}
(reference_constructs_from_temporary_v<Types, UTypes\&\&> || ...)
\end{codeblock}
is \tcode{true}.
\end{itemdescr}

\indexlibraryctor{tuple}%
Expand Down Expand Up @@ -1806,6 +1827,11 @@
\begin{codeblock}
!(is_convertible_v<decltype(get<I>(@\exposid{FWD}@(u))), Types> && ...)
\end{codeblock}
The constructor is defined as deleted if
\begin{codeblock}
(reference_constructs_from_temporary_v<Types, decltype(get<I>(@\exposid{FWD}@(u)))> || ...)
\end{codeblock}
is \tcode{true}.
\end{itemdescr}

\indexlibraryctor{tuple}%
Expand Down Expand Up @@ -1843,6 +1869,12 @@
!is_convertible_v<decltype(get<0>(@\exposid{FWD}@(u))), @$\tcode{T}_0$@> ||
!is_convertible_v<decltype(get<1>(@\exposid{FWD}@(u))), @$\tcode{T}_1$@>
\end{codeblock}
The constructor is defined as deleted if
\begin{codeblock}
reference_constructs_from_temporary_v<@$\tcode{T}_0$@, decltype(get<0>(@\exposid{FWD}@(u)))> ||
reference_constructs_from_temporary_v<@$\tcode{T}_1$@, decltype(get<1>(@\exposid{FWD}@(u)))>
\end{codeblock}
is \tcode{true}.
\end{itemdescr}

\indexlibraryctor{tuple}%
Expand Down Expand Up @@ -2404,6 +2436,13 @@
\end{itemdecl}

\begin{itemdescr}
\pnum
\mandates
If \tcode{tuple_size_v<remove_reference_t<Tuple>>} is 1,
then
\tcode{reference_constructs_from_temporary_v<T, decltype(get<0>(declval<Tuple>()))>}
is \tcode{false}.

\pnum
\effects
Given the exposition-only function:
Expand Down Expand Up @@ -16393,6 +16432,11 @@
if \tcode{R} is \cv{}~\keyword{void}, otherwise
\tcode{\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$)} implicitly converted
to \tcode{R}.
If
\tcode{reference_converts_from_temporary_v<R, decltype(\placeholdernc{INVOKE}(f, t$_1$, t$_2$, $\dotsc$, t$_N$))>}
is \tcode{true},
\tcode{\placeholdernc{INVOKE}<R>(f, t$_1$, t$_2$, $\dotsc$, t$_N$)}
is ill-formed.

\pnum
\indextext{call wrapper}%
Expand Down Expand Up @@ -19554,6 +19598,9 @@

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;
Expand Down Expand Up @@ -19826,6 +19873,12 @@
template<class T>
inline constexpr bool has_unique_object_representations_v
= has_unique_object_representations<T>::value;
template<class T, class U>
inline constexpr bool @\libglobal{reference_constructs_from_temporary_v}@
= reference_constructs_from_temporary<T, U>::value;
template<class T, class U>
inline 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>
Expand Down Expand Up @@ -20081,6 +20134,24 @@
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
Expand Down Expand Up @@ -20492,6 +20563,25 @@
\tcode{T} shall be a complete type, \cv{}~\keyword{void}, or
an array of unknown bound. \\ \rowsep

\indexlibraryglobal{reference_constructs_from_temporary}%
\tcode{template<class T, class U>}\br
\tcode{struct reference_constructs_from_temporary;} &
\tcode{conjunction_v<is_reference<T>, is_constructible<T, U>>}
is \tcode{true}, and
the initialization \tcode{T t(\exposidnc{VAL}<U>);} binds \tcode{t} to
a temporary object whose lifetime is extended\iref{class.temporary}. &
\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{conjunction_v<is_reference<T>, is_convertible<U, T>>} is \tcode{true},
and the initialization \tcode{T t = \exposidnc{VAL}<U>;} binds \tcode{t} to
a temporary object whose lifetime is extended\iref{class.temporary}. &
\tcode{T} and \tcode{U} shall be
complete types, \cv{}~\keyword{void}, or arrays of unknown bound. \\ \rowsep

\end{libreqtab3b}

\pnum
Expand Down