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

时间:2016-07-09 12:16:23

标签: c++ templates c++11 stdtuple boost-tuples

我无法从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);

注意:

  

除非所有std::is_constructible<Ti, const Ui&>::value的{​​{1}}为true,否则不参与重载决策。

istd::is_constructible<Foo<int>, int>::value。从GCC模板错误,我可以看到超载没有。 3:

true
而是选择

。为什么呢?

1 个答案:

答案 0 :(得分: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)) {}

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