This page is a snapshot from the LWG issues list, see theLibrary Active Issues List for more information and the meaning ofC++23 status.
tuple constructor constraints forUTypes&&... overloadsSection: 22.4.4.2[tuple.cnstr]Status:C++23Submitter: Matt CalabreseOpened: 2018-06-12Last modified: 2023-11-22
Priority:2
View otheractive issues in [tuple.cnstr].
View all otherissues in [tuple.cnstr].
View all issues withC++23 status.
Discussion:
Currently thetuple constructors of the form:
template<class... UTypes>EXPLICIT constexpr tuple(UTypes&&...);
are not properly constrained in that in the 1-elementtuple case, the constraints do no short-circuit whenthe constructor would be (incorrectly) considered as a possible copy/move constructor candidate. libc++ has aworkaround for this, but the additional short-circuiting does not actually appear in the working draft.
bool a = std::is_copy_constructible_v<std::tuple<any>>;
The above code will cause a compile error because of a recursive trait definition. The copy constructibilitycheck implies doing substitution into theUTypes&&... constructor overloads, which in turnwill check iftuple<any> is convertible to any, which in turn will check iftuple<any>is copy constructible (and so the trait is dependent on itself).
sizeof...(UTypes) == 1and the type, after applyingremove_cvref_t, is thetuple type itself, then we should forcesubstitution failure rather than checking any further constraints.[2018-06-23 after reflector discussion]
Priority set to 3
[2018-08-20, Jonathan provides wording]
[2018-08-20, Daniel comments]
The wording changes by this issue are very near to those suggested for LWG3155(i).
[2018-11 San Diego Thursday night issue processing]
Jonathan to update wording - using conjunction. Priority set to 2
Previous resolution [SUPERSEDED]:
This wording is relative toN4762.
Modify 22.4.4.2[tuple.cnstr] as indicated:
template<class... UTypes> explicit(see below) constexpr tuple(UTypes&&... u);-9-Effects: Initializes the elements in the tuple with the corresponding value in
-10-Remarks: This constructor shall not participate in overload resolution unlessstd::forward<UTypes>(u).sizeof...(Types) == sizeof...(UTypes)andsizeof...(Types) >= 1and(sizeof...(Types)> 1 || !is_same_v<remove_cvref_t<U0>, tuple>)andis_constructible_v<Ti, Ui&&>istruefor alli. The expression insideexplicitis equivalent to:!conjunction_v<is_convertible<UTypes, Types>...>
[2021-05-20 Tim updates wording]
The new wording below also resolves LWG3155(i), relating to anallocator_arg_t tag argument being treated by this constructor templateas converting to the first tuple element instead of as a tag. To minimizecollateral damage, this wording takes this constructor out of overload resolutiononly if the tuple is of size 2 or 3, the first argument is anallocator_arg_t,but the first tuple element isn't of typeallocator_arg_t (in both casesafter removing cv/ref qualifiers). This avoids damaging tuples that actuallycontain anallocator_arg_t as the first element (which can be formedduring uses-allocator construction, thanks touses_allocator_construction_args).
[2021-08-20; LWG telecon]
Set status to Tentatively Ready after telecon review.
[2021-10-14 Approved at October 2021 virtual plenary. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative toN4885, and also resolves LWG3155(i).
Modify 22.4.4.2[tuple.cnstr] as indicated:
template<class... UTypes> explicit(see below) constexpr tuple(UTypes&&... u);-?- Let
disambiguating-constraintbe:
(?.1) —
negation<is_same<remove_cvref_t<U0>, tuple>>ifsizeof...(Types)is 1;(?.2) — otherwise,
bool_constant<!is_same_v<remove_cvref_t<U0>, allocator_arg_t> || is_same_v<remove_cvref_t<T0>, allocator_arg_t>>ifsizeof...(Types)is 2 or 3;(?.3) — otherwise,
true_type.-12-Constraints:
(12.1) —
sizeof...(Types)equalssizeof...(UTypes),and(12.2) —
sizeof...(Types)≥ 1, and(12.3) —
conjunction_v<disambiguating-constraint, is_constructible<Types, UTypes>...>istrue.is_constructible_v<Ti, Ui>istruefor alli-13-Effects: Initializes the elements in the tuple with the corresponding value in
-14-Remarks: The expression insidestd::forward<UTypes>(u).explicitis equivalent to:!conjunction_v<is_convertible<UTypes, Types>...>