template constructor overload problems

Peter Dimov pdimov@mmltd.net
Sat Feb 16 06:17:00 GMT 2008


Pedro Lamarão:

...

> template <typename Element>
> struct tuple {
>
>   tuple () { }
>
>   template <typename UElements>
>   explicit
>   tuple (UElements&& elements)
>   { static_assert(!sizeof(UElements), "first constructor"); }
>
>   template <typename UElements>
>   tuple (tuple<UElements>&& foo)
>   { static_assert(!sizeof(UElements), "second constructor"); }
>
> };
>
> int
> main (int argc, char* argv[]) {
>
>   tuple<int> f1;
>   tuple<unsigned> f2(f1);
>
>   return 0;
> }
>
> mainline currently gives me this error:
>
> ../src/main.cpp: In constructor ‘tuple<Element>::tuple(UElements&&) [with 
> UElements = tuple<int>&, Element = unsigned int]’:
> ../src/main.cpp:21:   instantiated from here
> ../src/main.cpp:9: error: static assertion failed: "first constructor"
>
> If I take the first constructor out, I get "second constructor" in the 
> error, so both constructors are actually entering the overload set.
>
> Is this behaviour correct?

It seems correct to me. The first UElements is deduced from the lvalue f1 as 
tuple<int>&, giving the following overload set:

tuple( tuple<int>& elements );
tuple( tuple<int>&& foo );

with the first constructor being a better match for the lvalue.

You need to add

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

to handle this case (although it seems to me that a test with 
tuple<tuple<X>> might still fail).

> If the compiler is picking the correct constructor, isn't this a design 
> error in the tuple specification?

It's quite possible that there is. In my opinion, the constructor should 
take the elements by value:

    explicit tuple(_Elements... __elements);

and then use std::move to move __elements into place.



More information about the Libstdc++ mailing list