[c++0x] Problem with std::tuple's template converting constructors

Skip to first unread message

Pedro Lamarão

Feb 19, 2008, 5:45:39 PM2/19/08
The first version of this message went to comp.std.c++ but I've just
learned it is down.

The following issue was discussed in the libstdc++ development list
with Peter Dimov and Paolo Carlini while discussing the initialization
of tuple objects with "move-only" types.

Consider the following code.

template <typename Element>
struct tuple {

tuple () { }

template <typename UElements>
tuple (UElements&& elements)
{ static_assert(!sizeof(UElements), "first constructor"); }

template <typename UElements>
tuple (tuple<UElements>&& foo)
{ static_assert(!sizeof(UElements), "second constructor"); }


main (int argc, char* argv[]) {

tuple<int> f1;
tuple<unsigned> f2(f1); // A

return 0;

Line A above will always fails with the message "second constructor".
The overload set for constructing f2 is deduced as:

tuple( tuple<int>& elements ); // first constructor
tuple( tuple<int>&& foo ); // second constructor

with the first constructor a better match for the lvalue f1.
The obvious intent is for tuple objects to select the second

The proposed solution was to introduce a third constructor to better
match lvalue tuples.

template <typename UElements>
tuple (tuple<UElements>& foo)
{ static_assert(!sizeof(UElements), "third constructor"); }

Is this solution complete?


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Howard Hinnant

Feb 20, 2008, 12:44:33 AM2/20/08
In article
"Pedro Lamarão" <pedro....@gmail.com> wrote:

It fails if:

const tuple<int> f1;

which now binds back to "first constructor".

What we really need to do is constrain:

template <typename ...UElements>
tuple (UElements&&... elements)

such that tuple is constructible with UElements... . Currently the best
option for that is using concepts and std::Constructible (not yet in the

Failing that, the following is looking like a decent strategy to me:

template <typename ...Types>
struct tuple {

tuple () { }

explicit tuple(Types...)
{ static_assert(!sizeof(Types), "first constructor"); }

template <typename ...UElements>
tuple (tuple<UElements...>&& foo)
{ static_assert(!sizeof...(UElements), "second constructor"); }

template <typename ...UElements>
tuple (const tuple<UElements...>& foo)
{ static_assert(!sizeof...(UElements), "third constructor"); }

The implementation would move from the by value arguments in first


Reply all
Reply to author
0 new messages