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