Title
tuple constructor constraints for UTypes&&... overloads
Status
new
Section
[tuple.cnstr]
Submitter
Matt Calabrese

Created on 2018-06-12.00:00:00, last changed 2018-08-20.15:00:12.

Messages

Date: 2018-08-20.15:00:12

Proposed resolution:

This wording is relative to N4762.

  • Modify [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 std::forward<UTypes>(u).

    -10- Remarks: This constructor shall not participate in overload resolution unless sizeof...(Types) == sizeof...(UTypes) and sizeof...(Types) >= 1 and (sizeof...(Types) > 1 || !is_same_v<remove_cvref_t<U0>, tuple>) and is_constructible_v<Ti, Ui&&> is true for all i. The expression inside explicit is equivalent to:

    !conjunction_v<is_convertible<UTypes, Types>...>

Date: 2018-08-15.00:00:00

[ 2018-08-20, Daniel comments ]

The wording changes by this issue are very near to those suggested for LWG 3155.

Date: 2018-08-15.00:00:00

[ 2018-08-20, Jonathan provides wording ]

Date: 2018-06-23.00:00:00

[ 2018-06-23 after reflector discussion ]

Priority set to 3

Date: 2018-06-12.00:00:00

Currently the tuple constructors of the form:

template<class... UTypes>
EXPLICIT constexpr tuple(UTypes&&...);

are not properly constrained in that in the 1-element tuple case, the constraints do no short-circuit when the constructor would be (incorrectly) considered as a possible copy/move constructor candidate. libc++ has a workaround for this, but the additional short-circuiting does not actually appear in the working draft.

As an example of why this lack of short circuiting is a problem in practice, consider the following line:

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 constructibility check implies doing substitution into the UTypes&&... constructor overloads, which in turn will check if tuple<any> is convertible to any, which in turn will check if tuple<any> is copy constructible (and so the trait is dependent on itself).

I do not provide wording for the proposed fix in anticipation of requires clauses potentially changing how we do the specification, however, the basic solution should be similar to what we've done for other standard library types, which is to say that the very first constraint should be to check that if sizeof...(UTypes) == 1 and the type, after applying remove_cvref_t, is the tuple type itself, then we should force substitution failure rather than checking any further constraints.

History
Date User Action Args
2018-08-20 15:00:12adminsetmessages: + msg10047
2018-08-20 15:00:12adminsetmessages: + msg10046
2018-08-20 15:00:12adminsetmessages: + msg10045
2018-06-25 00:47:25adminsetmessages: + msg9951
2018-06-12 00:00:00admincreate