为什么 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
那样工作?
#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 和 libc++ 编译没有错误)
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);
注:
Does not participate in overload resolution unless
std::is_constructible<Ti, const Ui&>::value
is true
for all i
.
std::is_constructible<Foo<int>, int>::value
是 true
。从 GCC 模板错误中,我可以看到没有重载。 3:
template <class... UTypes>
explicit tuple(UTypes&&... args);
被选中。为什么?
重载 (4) 和 (5) 在传递 tuple&
时比 (3) 匹配更差:它们是 const&
和 &&
重载,而 (3) 完全匹配通过完美转发的魔法。
(3) 有效,因为您的 Foo(U&&)
构造函数过于贪婪。
将 SFINAE 检查添加到 Foo(U&&)
,以便在构建失败时无法匹配:
template <class U,
std::enable_if_t<std::is_convertible<U,int>{},int>* =nullptr
>
Foo(U &&u) : val(std::forward<U>(u)) {}
但是,右值大小写应该有效或不明确。查看您的实时示例的错误日志,我看到的唯一错误是左值错误。
我无法从 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 和 libc++ 编译没有错误)
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);
注:
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:
template <class... UTypes>
explicit tuple(UTypes&&... args);
被选中。为什么?
重载 (4) 和 (5) 在传递 tuple&
时比 (3) 匹配更差:它们是 const&
和 &&
重载,而 (3) 完全匹配通过完美转发的魔法。
(3) 有效,因为您的 Foo(U&&)
构造函数过于贪婪。
将 SFINAE 检查添加到 Foo(U&&)
,以便在构建失败时无法匹配:
template <class U,
std::enable_if_t<std::is_convertible<U,int>{},int>* =nullptr
>
Foo(U &&u) : val(std::forward<U>(u)) {}
但是,右值大小写应该有效或不明确。查看您的实时示例的错误日志,我看到的唯一错误是左值错误。