2013-05-26 23 views
5

Questo è quello che sto cercando di fare:modello di funzione variadic senza parametri formali

// base case 
void f() {} 

template <typename T, typename... Ts> 
void f() { 
    // do something with T 
    f<Ts...>(); 
} 

int main() { 
    f<int, float, char>(); 
    return 0; 
} 

Esso non può essere compilato:

prog.cpp: In instantiation of ‘void f() [with T = char; Ts = {}]’: 
prog.cpp:6:5: recursively required from ‘void f() [with T = float; Ts = {char}]’ 
prog.cpp:6:5: required from ‘void f() [with T = int; Ts = {float, char}]’ 
prog.cpp:10:25: required from here 
prog.cpp:6:5: error: no matching function for call to ‘f()’ 
prog.cpp:6:5: note: candidate is: 
prog.cpp:4:6: note: template<class T, class ... Ts> void f() 
prog.cpp:4:6: note: template argument deduction/substitution failed: 
prog.cpp:6:5: note: couldn't deduce template parameter ‘T’ 

This filo mostra un modo per risolvere questo problema, ma la il caso base deve essere un modello. Non mi piace molto, perché per quanto ho capito dovrò duplicare il codice che funziona con T. C'è un modo per evitarlo?

Finora mi si avvicinò con due soluzioni (http://ideone.com/nPqU0l):

template <typename...> struct types_helper {}; 

// base case 
void f(types_helper<>) {} 

template <typename T, typename... Ts> 
void f(types_helper<T, Ts...>) { 
    // do something with T 
    f(types_helper<Ts...>()); 
} 

int main() { 
    f(types_helper<int, float, char>()); 
    return 0; 
} 

http://ideone.com/yyg6y9:

#include <type_traits> 

struct end_of_list; 

template <typename T> 
void f() { 
    static_assert(std::is_same<T, end_of_list>::value, "error"); 
} 

template <typename T1, typename T2, typename... Ts> 
void f() { 
    // do something with T 
    f<T2, Ts...>(); 
} 

int main() { 
    f<int, float, char, end_of_list>(); 
    return 0; 
} 

Mi chiedo se c'è un modo migliore per farlo.

risposta

9

Un altro modo si sta trasformando la funzione non template f in una funzione di modello variadic che accetta zero o più argomenti del modello (l'altro f richiede uno o più argomenti del modello). Quindi per evitare l'ambiguità, SFINAE allontana questa funzione template quando il numero di argomenti non è zero. Bene, un codice è migliore di 1000 parole:

#include <type_traits> 

template <typename... Ts> 
typename std::enable_if<sizeof...(Ts) == 0>::type f() { 
} 

template <typename T, typename... Ts> 
void f() { 
    // do something with T 
    f<Ts...>(); 
} 
+1

Questo è bello. Anche se 'enable_if' sembra essere buggato in Visual Studio, quindi ho dovuto scriverlo come' decltype (typename std :: enable_if :: type()) '. – catscradle

+0

Correzione semplice e rapida al codice iniziale, mi piace. –

2

Dal momento che i modelli di classe può essere parzialmente specializzata, un'altra possibilità è quella di utilizzare i modelli di classe per fare il lavoro, e hanno la funzione delegato a loro:

template<typename... Ts> 
struct caller 
{ 
    static void call() { } // Base case, terminates recursion 
}; 

template<typename T, typename... Ts> 
struct caller<T, Ts...> 
{ 
    static void call() 
    { 
     // Do something with T 
     caller<Ts...>::call(); 
    } 
}; 

template<typename... Ts> 
void f() { 
    caller<Ts...>::call(); 
} 
+0

Oh, capisco. Stavo provando qualcosa come 'template <> struct caller <>' prima, che non ha funzionato. Grazie! – catscradle

+0

@catscradle: Sono contento che l'abbia aiutato :) –

Problemi correlati