2012-11-26 6 views
8

Se ho un modello che avvolge un container standard, sembra che posso ragionevolmente delegare facilmente il costruttore initializer_list:Opzionalmente costruzione di supporto initializer_list per i modelli di contenitori da imballaggio forse

template<typename T> 
struct holder { 
    T t_; 

    holder() : 
     t_() {} 

    holder(std::initializer_list<typename T::value_type> values) 
     : t_(values) {} 

}; 

Quindi, questo funziona bene con std :: vector , per esempio.

int main(int argc, char* argv[]) { 

    holder<std::vector<int>> y{1,2,3}; 
    return EXIT_SUCCESS; 
} 

Ma abbastanza, ovviamente, non funziona per T come 'int', o qualsiasi altro tipo che non ha un typedef value_type nidificato. Quindi, mi piacerebbe usare una sorta di enable_if o trucco simile per rendere il costruttore initializer_list non essere emesso a meno che T entrambi definiscano un typo type_tipo_node nid, ed è costruibile da std :: initializer_list.

Ho provato quanto segue, ma ancora non funziona, perché il compilatore (clang ++ 3.1 nel mio caso), viaggi ancora oltre l'invalido T :: value_type quando T è int:

holder(typename std::enable_if<std::is_constructible<T, std::initializer_list<typename T::value_type>>::value, std::initializer_list<typename T::value_type>>::type values) 
    : t_(values) {} 

Qualsiasi pensieri su come esprimere il concetto "date a questo modello su T un costruttore di lista di inizializzazione su T value_type, se e solo se T ha un typo di tipo value_f e è costruibile da una lista_inizialista di T :: value_type".

+0

è il 'initializer_list' passato per valore corretto, o dovrebbe essere passato per un certo tipo di riferimento? ('&&'?) –

+0

@MartinBa: pass by value è corretto (e consigliato) per 'std :: initializer_list'. –

+0

Un 'initializer_list' contiene solo un puntatore e una dimensione, quindi è ok passarlo per valore. I dati stessi non vengono copiati. –

risposta

4

SFINAE funziona solo sulla parametrizzazione dei parametri di modello (da cui la S in SFINAE). Le seguenti opere:

template<typename T> 
struct holder { 
    T t_; 

    holder() : 
     t_() {} 

    template<typename U = T> 
    holder(typename std::enable_if<std::is_constructible<U, std::initializer_list<typename U::value_type>>::value, 
    std::initializer_list<typename U::value_type>>::type values) 
    : t_(values) {} 

}; 

Se non si utilizza una funzione di modello, quindi tutta la classe sarebbe un'istanza per il tipo di int (nel tuo esempio), che porta a un errore di compilazione.

Nota che si potrebbe fare la firma funzione di più bello se è stato utilizzato un parametro di modello in più:

template<typename U = T, class = typename std::enable_if<std::is_constructible<U, std::initializer_list<typename U::value_type>>::value, bool>::type> 
    holder(std::initializer_list<typename U::value_type> values) 
    : t_(values) {} 
+0

Interessante, ma non funziona. Con la mia versione originale 'holder > y = {1, 2, 3}' funziona correttamente, ma almeno con il mio compilatore non funziona con la firma del costruttore revisionata. Si lamenta che il modello di costruttore candidato non è fattibile: richiede 1 argomento, ma 3 sono stati forniti ' – acm

+2

Non si può rilasciare enable_if e basta usare 'template holder (std :: initializer_list valori) '? –

+0

@VaughnCato che sembra funzionare meglio. – acm

Problemi correlati