Question

J'ai vu beaucoup de liens présentant les modèles variadique. Mais je ne l'ai jamais vu aucun exemple compilable qui illustre cette approche.

Quelqu'un pourrait-il me donner quelques liens où ces exemples compilable se trouvent?

Était-ce utile?

La solution

modèles VARIADIC font partie de la norme C ++ 0x qui est pas encore officiellement publié. Ils sont pris en charge par gcc depuis la version 4.3, mais vous devez activer le support de C ++ 0x en ajoutant le commutateur du compilateur std = c ++ 0x.

Autres conseils

L'un des exemples les plus simples possibles est la mise en œuvre suivante de max qui est même pas templated sur les types.

int maximum(int n)
{
    return n;
}

template<typename... Args>
int maximum(int n, Args... args)
{
    return max(n, maximum(args...));
}

Un peu plus complexe est la mise en œuvre de printf canonique:

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";
}

modèles VARIADIC sont une caractéristique C ++ 0x qui vise principalement les auteurs des bibliothèques génériques. Je ne vous attendre à les voir dans « code utilisateur ». Par exemple, dans le C ++ 0x bibliothèque standard, ils sont utilisés dans beaucoup d'endroits: std :: fonction, std :: async, std :: reference_wrapper, std :: tuple, std :: packaged_task, ...

Pour vous donner un exemple, je vais vous montrer comment un reference_wrapper peut être mis en œuvre par rapport aux modèles variadique:

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)...);
    }
};

est pas parfaitement conforme au projet de norme, mais il est censé être compilable avec peu de modifications. Il montre plusieurs C ++ 0x caractéristiques:

  • fonctions antérieures (désactivation du constructeur pour rvalues)
  • références rvalue (détection d'arguments rvalue au constructeur, le transfert parfait)
  • déduction de type via decltype
  • modèle de fonction bibliothèque standard declval pour créer des objets dans le but de construire une expression pour decltype (GCC ne vous avez pas encore offre ce modèle de fonction. Pour écrire vous-même)
  • modèles variadique (accepter un nombre quelconque de paramètres)

Le but du modèle de membre variadic est de transmettre des arguments à l'objet visé par ptr. Cela devrait fonctionner dans le cas où T est un type de pointeur de fonction ou d'un type de classe avec l'opérateur d'appel de fonction surchargée.

cheers! s

Un exemple très simple du modèle variadique:

Supposons que nous voulons avoir une fonction qui prend un nombre variable d'arguments et imprime tous. Ex:

print("Hello", 1, 3.14, 5L);

Pour cette fonctionnalité au travail, nous aurions besoin essentiellement deux fonctions:

première, une fonction qui prend un nombre variable d'arguments:

template<typename T, typename... Args>
void print(T t, Args ...args){
     std::cout << t << ", ";
     print(args...);
}

Quelques explications:

1.) Packs paramètres représentés par des points de suspension (...), qui apparaissent dans la liste des paramètres.

typename...Args 
        |  | << Optional whitespace. Can have multiple whitespaces in between them
    Args...args

Cela signifie que, tous ces sont les mêmes.

typename ...args
typename...args
typename   ...   args

Alors, vous n'avez pas à vous soucier de la position correcte les espaces blancs là-dedans. Bien que, l'OMI au plus un espace ne doit être utilisé comme une meilleure pratique.

2) Expansion Pack:. Un motif suivi par une ellipse

.
print(args...); //expand when you wish to use them

3.) Pack paramètre accepte zéro ou plus args de modèle. Donc, print(T t, Args... args) accepte un ou plusieurs args.


Une fois que vous comprenez que, nous pouvons visualiser le flux d'appels comme suit:

print("Hello", 1, 3.14, 5L);

se traduit par:

print(string, int, float, long);

qui appelle

print(int, float, long);

qui appelle

print(float, long);  // say Level 2

qui appelle

print(long);         // say Level 1

qui appelle

print();             // say Level 0

Si vous avez suivi le point # 3 attentivement, vous devez avoir réalisé que print(T t, Args... args) ne peut pas gérer l'appel au niveau 0.
Nous avons donc besoin d'une autre fonction ici avec le même nom de rattraper son retard à tous les niveaux> = 0.


seconde, en fonction de grab l'appel à la partie supérieure de la pile appel :

Catch au niveau 0:

void print(){}

ou, Catch au niveau 1:

template<typename T>
void print(T t){ std::cout << t;}

ou, Prise de niveau 2:

template<typename T, typename U>
void print(T t, U u){ std::cout << t << ", " << u;}

ainsi de suite ...

Chacune de ces fonctionnerait. Espérons que cela vous aide à la prochaine fois que vous allez à écrire une telle fonction ou classe.

Ceci est un exemple de modèles variadique que je mets sur mon blog: http://thenewcpp.wordpress.com/2011/ 11/23 / variadique-templates-part-1-2 /

Il compile. Il démontre trouver le plus grand type d'un groupe de types.

#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;
};

Avant C ++ 11, vous pouvez créer des modèles uniquement avec le nombre fixe de paramètres.

modèle Firts pour la fonction d'un paramètre.

modèle pour la deuxième fonction avec deux paramètres. ... i.e..

Depuis C ++ 11 vous pouvez écrire un seul modèle, compilateur génère fonction requise lui-même.

Bon exemple http://eli.thegreenplace.net/2014/variadic-templates-in- c /

autre syntaxe:. Expansion, par exemple

template<typename VAL, typename... KEYS>
class MyMaps
{
  typedef std::tuple< std::map<KEYS,VAL>... > Maps;
}

où:

MyMaps<int,int,string>:Maps

est maintenant fait:

std::tuple<std::map<int,int>,std::map<string,int> >
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top