2016-02-21 26 views
5

Dopo aver letto di un grande articolo True Story: Efficient Packing ho cercato di implementare tuple da solo come l'esercizio fisico:chiamata alla funzione è ambiguo quando il tipo di irrilevante definito come alias

#include <type_traits> 
#include <utility> 
#include <functional> 

template< std::size_t I, typename T > 
struct tuple_leaf { T value; }; 

template< std::size_t I, typename T > 
T & get(tuple_leaf< I, T > & leaf) 
{ return leaf.value; } 

template< typename Is, typename ...Ts > 
struct tuple_base; 

template< std::size_t ...Is, typename ...Ts > 
struct tuple_base< std::index_sequence<Is...>, Ts... > 
    : tuple_leaf< Is, Ts >... 
{ 
    using tuple_base_t = tuple_base; 
    template< typename ...Args, typename = std::enable_if_t< (sizeof...(Ts) == sizeof...(Args)) > > 
    tuple_base(Args &&... args) 
     : tuple_leaf< Is, Ts >{std::forward<Args>(args)}... 
    { ; } 
}; 

#if 0 
template< typename ...Ts > 
struct tuple 
    : tuple_base< std::index_sequence_for<Ts...>, Ts... > 
{ 
    using tuple_base_t = typename tuple::tuple_base_t; 
    using tuple_base_t::tuple_base_t; 
    using tuple_base_t::operator = ; 
}; 
#else 
// terse 
template< typename ...Ts > 
using tuple = tuple_base< std::index_sequence_for<Ts...>, Ts... >; 
#endif 

template< typename ...Args > 
tuple< Args &&... > 
forward_as_tuple(Args &&... args) 
{ return {std::forward<Args>(args)...}; } 

#include <tuple> 

int 
main() 
{ 
    tuple<int> t(1); 
    auto f = forward_as_tuple(t); 
    (void)f; 
    return 0; 
} 

Live example

Dopo l'implementazione di forward_as_tuple decido di modifica la definizione del tipo dal modello di classe a alias modello del modello di classe base, poiché tutto ciò di cui ho bisogno dalla suddivisione in classe tuple e la sua classe di implementazione tuple_base è solo std::index_sequence_for per il tipo di parametri del modello variadic pack - alias modello è esattamente lo strumento adatto a questo scopo. Dopo aver fatto che ho un errore (#if 0 caso):

error: call to 'forward_as_tuple' is ambiguous

Sembra strano per me, perché modello alias non fa nulla e d'altra parte forward_as_tuple chiamato per il tipo dallo stesso spazio dei nomi - Speravo che ADL dovrebbe funzionare per il caso sopra di sicuro.

Come spiegare la differenza tra le versioni di codice #if 1 e #if 0?

+0

'std :: index_sequence_for' diventa un argomento modello tipo del tipo dell'argomento di una chiamata di funzione, quindi' std' viene esaminato da ADL. BTW. Avrai lo stesso errore se usi 'tupla ' direttamente –

+0

@PiotrSkotnicki Momento sottile. Tengo sempre a mente che ADL è solo per tipi di argomenti di funzione, ma è anche per i parametri del modello. – Orient

+0

@PiotrSkotnicki 'tuple_base , int>>, tuple_base , int>>' è l'argomento della funzione. 'std :: index_sequence_for' è nel profondo. Cioè non è il nome del top template. Importa? – Orient

risposta

3

Adl causa la ricerca nel tipo passato e gli argomenti del modello passati.

Il non-alias tupla ha i suoi tipi e si trova come posizione per cercare ADL.

Il caso dell'alias tuple ha un std::index_sequence nell'elenco di argomenti del modello. Questo fa sì che std::forward_as_tuple venga considerato, oltre al tuo forward_as_tuple. Sono egualmente buone corrispondenze e si verifica un'ambiguità.

Come @Piotr indicato sopra nei commenti, tuple<std::string> mostra questo problema anche nel caso di non-alias.