2015-05-20 10 views
15

Vorrei applicare il tipo di modello variadico per essere identico a un tipo di modello impostato in precedenza. Nell'esempio seguente, vorrei che T e U fossero dello stesso tipo.Applicare il modello variadico di un determinato tipo

code on ideone.com

#include <iostream> 
#include <string> 

template<class T> 
struct Foo { 

    Foo(T val) { 
     std::cout << "Called single argument ctor" << std::endl; 
     // [...]  
    }  

    // How to enforce U to be the same type as T? 
    template<class... U> 
    Foo(T first, U... vals) { 
     std::cout << "Called multiple argument ctor" << std::endl; 
     // [...] 
    } 

}; 

int main() { 

    // Should work as expected. 
    Foo<int> single(1); 

    // Should work as expected. 
    Foo<int> multiple(1, 2, 3, 4, 5); 

    // Should't work (but works right now). The strings are not integers. 
    Foo<int> mixedtype(1, "a", "b", "c"); 

    // Also shouldn't work. (doesn't work right now, so that is good) 
    Foo<int> alsomixedtype(1, 1, "b", "c"); 
} 
+0

correlati: [Un metodo di template variadico per accettare un determinato numero di duplicati?] (Http://stackoverflow.com/questions/30179181) – Ruslan

risposta

11

Possiamo usare SFINAE per garantire che tutti i tipi U sono gli stessi T. Una cosa importante da notare è che U non è solo un tipo, come si intende, ma un elenco di tipi possibilmente disparati.

template<class... U, std::enable_if_t<all_same<T, U...>::value>* = nullptr> 
Foo(T first, U... vals) { 
    std::cout << "Called multiple argument ctor" << std::endl; 
    // [...] 
} 

std::enable_if_t da C++ 14. Se questa non è un'opzione per te, basta usare std::enable_if.

typename std::enable_if<all_same<T, U...>::value>::type* = nullptr> 

all_same può essere implementato in un sacco di modi diversi. Qui è un metodo che mi piace utilizzare confezioni booleani:

namespace detail 
{ 
    template<bool...> struct bool_pack; 
    template<bool... bs> 
    //if any are false, they'll be shifted in the second version, so types won't match 
    using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>; 
} 
template <typename... Ts> 
using all_true = detail::all_true<Ts::value...>; 

template <typename T, typename... Ts> 
using all_same = all_true<std::is_same<T,Ts>...>; 
0

Senza attuazione di all_same si potrebbe anche cambiare il codice del costruttore come segue:

template<class F, typename = typename enable_if<is_same<F, T>::value>::type, class... U> 
    Foo(F first, U... vals): Foo(vals...) { 
    std::cout << "Called multiple argument ctor" << std::endl; 
    // [...] 
} 

is_same è la funzione in uno STL <type_traits>

+0

hard-coding del tipo 'int' limita l'uso di questa funzione, – Jagannath

+0

@Jagannath effettivamente i t può essere qualsiasi cosa anche per es. nullo poichè è solo per determinare se il tipo è valido –

+0

@Jagannath la cosa fondamentale è che chiamiamo il costruttore del costrutto di tipo interno in modo ricorsivo fino a ottenere solo un parametro –

Problemi correlati