我无法从 std::tuple
兼容类型中逐个元素地初始化 std::tuple
元素 . 为什么它不像 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或Clang和libstdc无法编译,但 Clang and libc++ compiles without errors )
std::tuple
没有按元素构造,它实例化 Foo<int>::Foo<std::tuple<int>>
而不是 Foo<int>::Foo<int>
. 我认为std::tuple::tuple overloads no. 4 and 5正是出于这个目的:
template <class... UTypes>
tuple(const tuple<UTypes...>& other);
template <class... UTypes>
tuple(tuple<UTypes...>&& other);
注意:
除非std :: is_constructible <Ti,const Ui&> :: value对所有i都为真,否则不参与重载决策 .
std::is_constructible<Foo<int>, int>::value
是 true
. 从GCC模板错误,我可以看到超载没有 . 3:
template <class... UTypes>
explicit tuple(UTypes&&... args);
而是被选中 . 为什么?
1 回答
传递
tuple&
时,重载(4)和(5)是比(3)更差的匹配:它们是const&
和&&
重载,而(3)完全匹配完美转发的魔力 .(3)有效是因为你的
Foo(U&&)
构造函数过于贪婪 .将SFINAE检查添加到
Foo(U&&)
,以便在构建失败时无法匹配:然而,右值情况应该起作用或模糊不清 . 查看实时示例的错误日志,我看到的唯一错误是左值 .