为什么std :: tuple不能用std :: tuple兼容类型构造元素?

Log*_*uff 12 c++ templates boost-tuples c++11 stdtuple

我无法std::tuplestd::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
}
Run Code Online (Sandbox Code Playgroud)

住在Coliru(GCC或Clang和libstdc ++不编译,但 Clang和libc ++编译没有错误)


std::tuple不做元素构造而是实例化Foo<int>::Foo<std::tuple<int>>而不是Foo<int>::Foo<int>.我认为std::tuple::tuple超载没有.4和5完全是为了这个目的:

template <class... UTypes>
tuple(const tuple<UTypes...>& other);

template <class... UTypes>
tuple(tuple<UTypes...>&& other);
Run Code Online (Sandbox Code Playgroud)

注意:

除非
std::is_constructible<Ti, const Ui&>::valuetrue为了所有人,否则不参与重载决策i.

std::is_constructible<Foo<int>, int>::valuetrue.从GCC模板错误,我可以看到超载没有.3:

template <class... UTypes>
explicit tuple(UTypes&&... args);
Run Code Online (Sandbox Code Playgroud)

而是被选中.为什么?

Yak*_*ont 3

当传递 a 时,重载 (4) 和 (5) 比 (3) 匹配更差tuple&:它们是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)) {}
Run Code Online (Sandbox Code Playgroud)

然而,右值的情况应该有效或不明确。查看您的实例的错误日志,我看到的唯一错误是左值错误。