2016-07-09 67 views
9

Non riesco a inizializzare gli elementi std::tuple element-wise da un std::tuple di tipi compatibili. Perché non funziona come con boost::tuple?Perché non posso std :: tuple essere costruito in base agli elementi con una tupla di tipi :: std :: compatibili?

#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 o Clang e libstdC++ non compila, tuttavia Clang e libC++ compila senza errori)


std::tuple non sta facendo elemento-saggio costruzione e istanzia Foo<int>::Foo<std::tuple<int>> anziché Foo<int>::Foo<int> . Ho pensato std::tuple::tuple overloads no. 4 and 5 erano esattamente a tale scopo:

template <class... UTypes> 
tuple(const tuple<UTypes...>& other); 

template <class... UTypes> 
tuple(tuple<UTypes...>&& other); 

Nota:

non partecipa nella risoluzione di sovraccarico a meno
std::is_constructible<Ti, const Ui&>::value è true per tutti i.

std::is_constructible<Foo<int>, int>::value è true. Dall'errore del modello GCC, posso vedere che il sovraccarico no. 3:

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

è selezionato. Perché?

+0

Ok, non funziona con '-std = libstdC++', ma funziona con '-std = libC++' su Clang. Deve essere un problema di implementazione. – LogicStuff

+2

Segnala un bug nel bugzilla di gcc. –

+3

Questa domanda fornirà comunque informazioni preziose per coloro che incontreranno lo stesso problema. Dirà loro che il problema è con l'implementazione della libreria standard e non nel loro codice. Ci sono molti obiettivi comuni di dupe che sono la spiegazione del particolare bug di implementazione (MinGW e 'stoi' per esempio) –

risposta

3

sovraccarichi (4) e (5) sono le partite più poveri rispetto (3) quando viene passato un tuple&: sono const& e && sovraccarichi, mentre (3) corrisponde esattamente attraverso la magia di inoltro perfetta.

(3) è valido perché il costruttore Foo(U&&) è eccessivamente goloso.

Aggiungi controlli SFINAE a Foo(U&&) in modo che non riesce a corrispondere quando non riesce a costruire:

template <class U, 
    std::enable_if_t<std::is_convertible<U,int>{},int>* =nullptr 
> 
Foo(U &&u) : val(std::forward<U>(u)) {} 

Il caso rvalue dovrebbe, tuttavia, il lavoro o di essere ambiguo. Guardando il log degli errori del tuo esempio live, l'unico errore che vedo è quello di lvalue.

+0

Wow, funziona! (L'ho cambiato in 'typename = std :: enable_if_t :: value>') Perché c'è una differenza tra libstdC++ e libC++? Si tratta di un dettaglio di implementazione, non specificato dallo standard? Dovremmo segnalarlo e a chi? – LogicStuff

+1

Per il problema di abbinamento: 'const auto b' continua a riprodursi. È necessario segnalarlo a libstdC++ (ad esempio bugzilla di gcc). Inoltre, potresti voler chiedere sul forum isocpp.org sull'aggiunta di un costruttore che accetta un lvalue di tuple non const, quindi è una corrispondenza migliore. –

+1

@logic grazie per aver corretto gli errori di battitura, ma la soluzione 'class =' è peggiore di quella di 'int * = nullptr'. Nel caso di sovraccarichi multipli, 'class =' fallisce, mentre 'int * =' no. – Yakk

Problemi correlati