2016-07-09 3 views
9

Я не могу инициализировать элементы std::tuple элементов из std::tuple совместимых типов. Почему он не работает как с boost::tuple?Почему std :: tuple не может быть поэтапно построен с использованием std :: 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 не true для всех i.

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

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

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

+0

Хорошо, он не работает с '-std = libstdC++', но работает с '-std = libC++' на Clang. Должна быть проблема внедрения. – LogicStuff

+2

Пожалуйста, укажите ошибку в bugzilla gcc. –

+3

Этот вопрос по-прежнему будет давать ценную информацию для тех, кто столкнется с одной и той же проблемой. Он скажет им, что проблема связана со стандартной реализацией библиотеки, а не с кодом. Есть много общих целей обмана, которые являются объяснением конкретной ошибки реализации (например, MinGW и 'stoi') –

ответ

3

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

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

+0

Вау, это работает! (Я изменил его на 'typename = std :: enable_if_t :: value>'). Почему существует разница между libstdC++ и libC++? Является ли это деталью реализации, не указанной стандартом? Должны ли мы сообщать об этом и кому? – LogicStuff

+1

Для соответствующей проблемы: 'const auto b' все еще воспроизводится. Вам нужно сообщить об этом в libstdC++ (т. Е. Bugzilla gcc). Кроме того, вы можете спросить на форуме isocpp.org о добавлении конструктора, который принимает неконстантный кортеж lvalue, поэтому он лучше подходит. –

+1

@logic спасибо за исправление опечаток, но решение 'class =' хуже, чем 'int * = nullptr'. В случае множественных перегрузок 'class =' терпит неудачу, а 'int * =' - нет. – Yakk