I can't initialize std::tuple
elements element-wise from a std::tuple
of compatible types. Why doesn't it work as with boost::tuple
?
#include <tuple>
#include <boost/tuple/tuple.hpp>
template <typename T>
struct Foo
{
// error: cannot convert 'std::tuple<int>' to 'int' in initialization
template <typename U>
Foo(U &&u) : val(std::forward<U>(u)) {}
T val;
};
int main()
{
boost::tuple<Foo<int>>{boost::tuple<int>{}}; // ok
auto a = boost::tuple<int>{};
boost::tuple<Foo<int>>{a}; // ok
std::tuple<Foo<int>>{std::tuple<int>{}}; // fails with rvalue
auto b = std::tuple<int>{};
std::tuple<Foo<int>>{b}; // fails with lvalue
}
Live on Coliru (GCC or Clang and libstdc++ does not compile, however Clang and libc++ compiles without errors)
std::tuple
is not doing element-wise construction and it instantiates Foo<int>::Foo<std::tuple<int>>
instead of Foo<int>::Foo<int>
. I thought std::tuple::tuple
overloads no. 4 and 5 were exactly for that purpose:
template <class... UTypes>
tuple(const tuple<UTypes...>& other);
template <class... UTypes>
tuple(tuple<UTypes...>&& other);
Note:
Does not participate in overload resolution unless
std::is_constructible<Ti, const Ui&>::value
istrue
for alli
.
std::is_constructible<Foo<int>, int>::value
is true
. From the GCC template error, I can see that overload no. 3:
template <class... UTypes>
explicit tuple(UTypes&&... args);
is selected instead. Why?
Overloads (4) and (5) are poorer matches than (3) when passed a tuple&
: they are const&
and &&
overloads, while (3) matches exactly through the magic of perfect forwarding.
(3) is valid because your Foo(U&&)
constructor is overly greedy.
Add SFINAE checks to Foo(U&&)
so that it fails to match when it fails to build:
template <class U,
std::enable_if_t<std::is_convertible<U,int>{},int>* =nullptr
>
Foo(U &&u) : val(std::forward<U>(u)) {}
The rvalue case should, however, work or be ambiguous. Looking at the error log of your live example, the only error I see is with the lvalue one.
来源:https://stackoverflow.com/questions/38281724/why-cant-stdtuple-be-element-wise-constructed-with-a-stdtuple-of-compatible