首页 文章

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

提问于
浏览
11

我无法从 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>::valuetrue . 从GCC模板错误,我可以看到超载没有 . 3:

template <class... UTypes>
explicit tuple(UTypes&&... args);

而是被选中 . 为什么?

1 回答

  • 3

    传递 tuple& 时,重载(4)和(5)是比(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)) {}
    

    然而,右值情况应该起作用或模糊不清 . 查看实时示例的错误日志,我看到的唯一错误是左值 .

相关问题