This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
tuple
can create dangling references from tuple-like
Section: 22.4.4.2 [tuple.cnstr] Status: WP Submitter: Jonathan Wakely Opened: 2024-01-24 Last modified: 2024-04-02
Priority: Not Prioritized
View other active issues in [tuple.cnstr].
View all other issues in [tuple.cnstr].
View all issues with WP status.
Discussion:
P2165R4
(Compatibility between tuple, pair and tuple-like objects)
added two new constructors to std::tuple
:
template<tuple-likeUTuple>
constexpr explicit(see below ) tuple(UTuple&& u);
and the allocator-extended equivalent. Unlike the existing constructors taking a single parameter of tuple type, these new constructors are not defined as deleted if they would create a dangling reference to a temporary. The existing constructors gained that restriction from P2255R2 (A type trait to detect reference binding to temporary) which was approved one meeting before P2165R4 so LWG seem to have missed the inconsistency.
The proposal also added a new constructor for std::pair
:
template<pair-like P> constexpr explicit(see below) pair(P&& p);
This is deleted if it would create a dangling reference, although that seems to be an almost accidental consequence of adding the new signature after existing ones which already have the Remarks: about being deleted.
[2024-03-12; Reflector poll]
Set status to Tentatively Ready after eleven votes in favour during reflector poll.
[Tokyo 2024-03-23; Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4971.
Modify 22.4.4.2 [tuple.cnstr] as indicated:
template<tuple-like UTuple> constexpr explicit(see below) tuple(UTuple&& u);
-28- Let
I
be the pack0, 1, ..., (sizeof...(Types) - 1)
.-29- Constraints:
- (29.1) –
different-from<UTuple, tuple>
(25.5.2 [range.utility.helpers]) istrue
,- (29.2) –
remove_cvref_t<UTuple>
is not a specialization ofranges::subrange
,- (29.3) –
sizeof...(Types)
equalstuple_size_v<remove_cvref_t<UTuple>>
,- (29.4) –
(is_constructible_v<Types, decltype(get<I>(std::forward<UTuple>(u)))> && ...)
istrue
, and- (29.5) – either
sizeof...(Types)
is not 1, or (whenTypes...
expands toT
)is_convertible_v<UTuple, T>
andis_constructible_v<T, UTuple>
are bothfalse
.-30- Effects: For all i, initializes the ith element of
*this
withget<i>(std::forward<UTuple>(u))
.-31- Remarks: The expression inside
explicit
is equivalent to:!(is_convertible_v<decltype(get<I>(std::forward<UTuple>(u))), Types> && ...)
The constructor is defined as deleted if
(reference_constructs_from_temporary_v<Types, decltype(get<I>(std::forward<UTuple>(u)))> || ...)
is
true
.