modelli variadic
-
30-09-2019 - |
Domanda
ho visto un sacco di link che introducono i modelli variadic. Ma non ho mai visto alcun esempio compilabile che illustra questo approccio.
Potrebbe qualcuno fornirmi qualche link in cui tali esempi compilabili possono essere trovati?
Soluzione
modelli variadic sono parte dello standard C ++ 0x che non è ancora ufficialmente rilasciato. Sono supportati da gcc dalla versione 4.3, ma è necessario abilitare il supporto per C ++ 0x, aggiungendo l'opzione del compilatore -std = C ++ 0x.
Altri suggerimenti
Uno dei più semplici esempi possibili è la seguente implementazione di max
che non è nemmeno templato sui tipi.
int maximum(int n)
{
return n;
}
template<typename... Args>
int maximum(int n, Args... args)
{
return max(n, maximum(args...));
}
Solo un po 'più complesso è l'implementazione printf
canonica:
void printf(const char *s)
{
while (*s)
{
if (*s == '%' && *(++s) != '%')
throw "invalid format string: missing arguments";
std::cout << *s++;
}
}
template<typename T, typename... Args>
void printf(const char* s, T value, Args... args)
{
while (*s)
{
if (*s == '%' && *(++s) != '%')
{
std::cout << value;
printf(s, args...); // call even when *s == 0 to detect extra arguments
return;
}
std::cout << *s++;
}
throw "extra arguments provided to printf";
}
modelli variadic sono una caratteristica C ++ 0x che prende di mira in primo luogo gli autori di librerie generiche. Non mi aspetto di vederli in "codice utente". Ad esempio, nel C ++ 0x libreria standard sono utilizzati in un sacco di posti: std :: funzione std :: asincrona, std :: reference_wrapper, std :: tuple, std :: packaged_task, ...
Per fare un esempio io vi mostrerò come un reference_wrapper potrebbe essere attuata per quanto riguarda i modelli variadic:
template<class T>
class reference_wrapper
{
T *ptr;
public:
explicit reference_wrapper(T& thing) : ptr(&thing) {}
explicit reference_wrapper(T&& ) = delete;
operator T&() const {return *ptr;}
template<class... Args>
decltype( declval<T&>()(declval<Args>()...) )
operator()(Args&&... args) const
{
return (*ptr)(forward<Args>(args)...);
}
};
Questa non è perfettamente conforme al progetto di norma, ma si suppone che sia compilabile con poche modifiche. Dimostra multipla C ++ 0x caratteristiche:
- funzioni eliminati (disabilitando la funzione di costruzione per rvalues)
- riferimenti rvalue (rilevazione argomenti rvalue al costruttore, l'inoltro perfetto)
- tipo deduzione tramite
decltype
- standard di template funzione di libreria
declval
per creare gli oggetti ai fini della costruzione di un'espressione perdecltype
(GCC non offre ancora questo modello di funzione. Devi scrivere voi stessi) - modelli variadic (accettare un numero arbitrario di parametri)
Lo scopo del modello membro variadic è quello di inoltrare argomenti per l'oggetto a cui si riferisce ptr
. Questo dovrebbe funzionare in caso T è un tipo puntatore a funzione o un tipo di classe con operatore chiamata di funzione sovraccaricata.
evviva! s
Un esempio molto semplice di template variadic:
Supponiamo di voler avere una funzione che prende numero variabile di argomenti e li tutte le stampe. Per esempio:
print("Hello", 1, 3.14, 5L);
Per tale funzionalità per il lavoro, ci sarebbe fondamentalmente richiede due funzioni:
prima, una funzione che prende numero variabile di argomenti:
template<typename T, typename... Args>
void print(T t, Args ...args){
std::cout << t << ", ";
print(args...);
}
Qualche spiegazione:
1.) Pacchetti parametro indicato da puntini di sospensione (...), che appaiono nella lista dei parametri.
typename...Args
| | << Optional whitespace. Can have multiple whitespaces in between them
Args...args
Ciò significa che, tutti questi sono gli stessi.
typename ...args
typename...args
typename ... args
Quindi, non c'è bisogno di preoccuparsi della corretta posizione del spazi in là. Anche se, IMO al massimo uno spazio bianco dovrebbe essere utilizzato come best practice.
2) Expansion Pack:. Un modello seguito da puntini di sospensione
.print(args...); //expand when you wish to use them
3.) Parametro pacchetto accetta zero o più args template. Così, print(T t, Args... args)
accetta uno o più args.
Una volta capito questo, siamo in grado di visualizzare il flusso di chiamata, come di seguito:
print("Hello", 1, 3.14, 5L);
si traduce in:
print(string, int, float, long);
che le chiamate
print(int, float, long);
che le chiamate
print(float, long); // say Level 2
che le chiamate
print(long); // say Level 1
che le chiamate
print(); // say Level 0
Se avete seguito il Punto # 3 con cura, è necessario avere capito che print(T t, Args... args)
non può gestire chiamate al livello 0.
Quindi abbiamo bisogno di un'altra funzione qui con lo stesso nome di raggiungere a qualsiasi livello> = 0.
seconda, una funzione per grab la chiamata nella parte superiore dello stack di chiamate :
Cattura a livello 0:
void print(){}
o, fermo al livello 1:
template<typename T>
void print(T t){ std::cout << t;}
o, fermo al livello 2:
template<typename T, typename U>
void print(T t, U u){ std::cout << t << ", " << u;}
così via ...
Uno di questi avrebbe funzionato. Spero che questo ti aiuta prossima volta che andate a scrivere tale funzione o di classe.
- Wikipedia è buon punto di partenza.
- Gregor, Douglas; Jaakko Järvi; Gary Powell (9 settembre 2006). "Variadic Modelli (Revision 3)".
Questo è un esempio di modelli variadic che ho messo sul mio blog: http://thenewcpp.wordpress.com/2011/ 11/23 / variadic-templates-parte-1-2 /
Compila. Dimostra trovare il tipo più grande da un gruppo di tipi.
#include <type_traits>
template <typename... Args>
struct find_biggest;
//the biggest of one thing is that one thing
template <typename First>
struct find_biggest<First>
{
typedef First type;
};
//the biggest of everything in Args and First
template <typename First, typename... Args>
struct find_biggest<First, Args...>
{
typedef typename find_biggest<Args...>::type next;
typedef typename std::conditional
<
sizeof(First) >= sizeof(next),
First,
next
>::type type;
};
Prima di C ++ 11, è possibile creare template solo con il numero fisso di parametri.
modello Firts per la funzione con un parametro.
Secondo modello per la funzione con due parametri. ... cioè.
Dato che C ++ 11 è possibile scrivere un solo modello, compilatore genererà funzione richiesta stessa.
Buon esempio http://eli.thegreenplace.net/2014/variadic-templates-in- c /
un'altra sintassi:. Espansione, per esempio
template<typename VAL, typename... KEYS>
class MyMaps
{
typedef std::tuple< std::map<KEYS,VAL>... > Maps;
}
quindi:
MyMaps<int,int,string>:Maps
è ora realtà:
std::tuple<std::map<int,int>,std::map<string,int> >