为什么不能用兼容类型的std :: tuple来按元素构造std :: tuple? [英] Why can't std::tuple be element-wise constructed with a std::tuple of compatible types?
问题描述
我无法从兼容类型的std::tuple
逐元素初始化std::tuple
元素.为什么它不能与boost::tuple
一起使用?
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
}
在Coliru上生活 (GCC或Clang和libstdc ++无法编译,但是 Clang和libc ++编译没有错误)
std::tuple
没有进行元素构造,它实例化了Foo<int>::Foo<std::tuple<int>>
而不是Foo<int>::Foo<int>
.我以为 std::tuple::tuple
不超载. 4和5 正是出于这个目的:
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);
注意:
除非所有
i
的
std::is_constructible<Ti, const Ui&>::value
为true
,否则不参与重载解析.
Does not participate in overload resolution unless
std::is_constructible<Ti, const Ui&>::value
istrue
for alli
.
std::is_constructible<Foo<int>, int>::value
是true
.从GCC模板错误中,我可以看到没有过载. 3:
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?
推荐答案
在传递tuple&
时,重载(4)和(5)比(3)更差:它们是const&
和&&
重载,而(3)通过完美转发的魔力完全匹配.
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)有效,因为您的Foo(U&&)
构造函数过于贪婪.
(3) is valid because your Foo(U&&)
constructor is overly greedy.
将SFINAE检查添加到Foo(U&&)
,以便在构建失败时不匹配:
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.
这篇关于为什么不能用兼容类型的std :: tuple来按元素构造std :: tuple?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!