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?

È stato utile?

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 per decltype (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.

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> >
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top