This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.
pair
and tuple
Section: 22.3.2 [pairs.pair], 22.4.4.2 [tuple.cnstr] Status: Resolved Submitter: Daniel Krügler Opened: 2010-03-20 Last modified: 2016-01-28
Priority: Not Prioritized
View other active issues in [pairs.pair].
View all other issues in [pairs.pair].
View all issues with Resolved status.
Discussion:
In analogy to library defect 811(i), tuple
's variadic constructor
template <class... UTypes> explicit tuple(UTypes&&... u);
creates the same problem as pair:
#include <tuple> int main() { std::tuple<char*> p(0); }
produces a similar compile error for a recent gcc implementation.
I suggest to follow the same resolution path as has been applied to
pair
's corresponding c'tor, that is require that these c'tors should
not participate in overload resolution, if the arguments are not implicitly
convertible to the element types.
Further-on both pair
and tuple
provide converting constructors
from different pairs
/tuples
that should be not available, if
the corresponding element types are not implicitly convertible. It seems
astonishing that in the following example
struct A { explicit A(int); }; A a = 1; // Error std::tuple<A> ta = std::make_tuple(1); // # OK?
the initialization marked with # could be well-formed.
[ Only constraints on constructors are suggested. Adding similar constraints on assignment operators is considered as QoI, because the assigments wouldn't be well-formed anyway. ]
Following 22.3.2 [pairs.pair]/5 add a new Remarks element:
template<class U, class V> pair(const pair<U, V>& p);5 Effects: Initializes members from the corresponding members of the argument
, performing implicit conversions as needed.Remarks: This constructor shall not participate in overload resolution unless
U
is implicitly convertible tofirst_type
andV
is implicitly convertible tosecond_type
.
Following 22.3.2 [pairs.pair]/6 add a new Remarks element:
template<class U, class V> pair(pair<U, V>&& p);6 Effects: The constructor initializes
first
withstd::move(p.first)
and second withstd::move(p.second)
.Remarks: This constructor shall not participate in overload resolution unless
U
is implicitly convertible tofirst_type
andV
is implicitly convertible tosecond_type
.
Following 22.4.4.2 [tuple.cnstr]/7 add a new Remarks element:
template <class... UTypes> explicit tuple(UTypes&&... u);6 Requires: Each type in
Types
shall satisfy the requirements ofMoveConstructible
(Table 33) from the corresponding type inUTypes
.sizeof...(Types) == sizeof...(UTypes)
.7 Effects: Initializes the elements in the
tuple
with the corresponding value instd::forward<UTypes>(u)
.Remarks: This constructor shall not participate in overload resolution unless each type in
UTypes
is implicitly convertible to its corresponding type inTypes
.
Following 22.4.4.2 [tuple.cnstr]/13 add a new Remarks element:
template <class... UTypes> tuple(const tuple<UTypes...>& u);12 Requires: Each type in
Types
shall be constructible from the corresponding type inUTypes
.sizeof...(Types) == sizeof...(UTypes)
.13 Effects: Constructs each element of
*this
with the corresponding element ofu
.Remarks: This constructor shall not participate in overload resolution unless each type in
UTypes
is implicitly convertible to its corresponding type inTypes
.14 [Note:
enable_if
can be used to make the converting constructor and assignment operator exist only in the cases where the source and target have the same number of elements. — end note]
Following 22.4.4.2 [tuple.cnstr]/16 add a new Remarks element:
template <class... UTypes> tuple(tuple<UTypes...>&& u);15 Requires: Each type in
Types
shall shall satisfy the requirements ofMoveConstructible
(Table 33) from the corresponding type inUTypes
.sizeof...(Types) == sizeof...(UTypes)
.16 Effects: Move-constructs each element of
*this
with the corresponding element ofu
.Remarks: This constructor shall not participate in overload resolution unless each type in
UTypes
is implicitly convertible to its corresponding type inTypes
.[Note:
enable_if
can be used to make the converting constructor and assignment operator exist only in the cases where the source and target have the same number of elements. — end note]
Following 22.4.4.2 [tuple.cnstr]/18 add a new Remarks element:
template <class U1, class U2> tuple(const pair<U1, U2>& u);17 Requires: The first type in
Types
shall be constructible fromU1
and the second type inTypes
shall be constructible fromU2
.sizeof...(Types) == 2
.18 Effects: Constructs the first element with
u.first
and the second element withu.second
.Remarks: This constructor shall not participate in overload resolution unless
U1
is implicitly convertible to the first type inTypes
andU2
is implicitly convertible to the second type inTypes
.
Following 22.4.4.2 [tuple.cnstr]/20 add a new Remarks element:
template <class U1, class U2> tuple(pair<U1, U2>&& u);19 Requires: The first type in
Types
shall shall satisfy the requirements ofMoveConstructible
(Table 33) fromU1
and the second type inTypes
shall be move-constructible fromU2
.sizeof...(Types) == 2
.20 Effects: Constructs the first element with
std::move(u.first)
and the second element withstd::move(u.second)
Remarks: This constructor shall not participate in overload resolution unless
U1
is implicitly convertible to the first type inTypes
andU2
is implicitly convertible to the second type inTypes
.
[ 2010-10-24 Daniel adds: ]
Accepting n3140 would solve this issue.
Proposed resolution:
See n3140.