Почему std :: tuple не может быть поэлементно создан с помощью std :: tuple совместимых типов?

Я не могу инициализировать 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
}

Жить на Колиру (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);

Замечания:

Не участвует в разрешении перегрузки, если только
std::is_constructible<Ti, const Ui&>::value является true для всех i,

std::is_constructible<Foo<int>, int>::value является true, Из ошибки шаблона GCC я вижу, что перегрузки нет. 3:

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

выбран вместо Зачем?

11

Решение

Перегрузки (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)) {}

Тем не менее, случай должен работать или быть неоднозначным. Глядя на журнал ошибок вашего живого примера, я вижу только ошибку lvalue.

3

Другие решения

Других решений пока нет …