为什么 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>::valuetrue。从 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)) {}

但是,右值大小写应该有效或不明确。查看您的实时示例的错误日志,我看到的唯一错误是左值错误。