2017-05-18 8 views
1

Plus tôt, j'ai demandé ce question environ std::variant. Considérant que les types détenus par la variante sont tous imprimables par std::cout, existe-t-il un moyen simple de mettre en œuvre un visiteur?Un modèle pourrait-il fonctionner pour la visite de std :: variant?

Here par exemple, tout en bas, vous avez plusieurs lambdas pour couvrir chaque type, mais tous font la même chose (sauf std::string): std::cout << arg << ' ';. Y a-t-il un moyen de ne pas me répéter?

std::visit(overloaded { 
      [](int arg) { std::cout << arg; }, 
      [](long arg) { std::cout << arg; }, 
      [](double arg) { std::cout << arg; } 
      // I removed the std::string case 
     }, v); // v is the std::variant 

et écrire à la place:

std::visit( [](auto arg) { std::cout << arg; }, v); 

ou quelque chose comme:

template<typename T> 
void printer(T arg) {std::cout << arg; } 
//....... 
std::visit(printer, v); 
+2

Le deuxième bloc (avec le lambda générique) devrait fonctionner. Le troisième bloc (avec la fonction de modèle) ne fonctionnera pas parce que le modèle n'est pas une fonction ou un objet unique. Vous pouvez écrire votre propre callable avec un template 'operator()': 'struct printer {template void opérateur() (T arg) {std :: cout << arg; }}; std :: visit (printer {}, v); '(qui est à peu près équivalent au lambda générique). –

+6

Lorsque nous continuons à ajouter la balise [tag: C++] à vos questions, il y a une raison. S'il vous plaît faites-le vous-même à partir de maintenant. –

Répondre

2

Pas besoin de copier

std::visit( [](auto&& arg) { std::cout << arg; }, v); 

cela prend arg par référence (expédition). Je ne m'en préoccupe pas; Je me fiche de savoir si c'est vraiment une valeur ou une valeur.

La fonction de modèle ne fonctionne pas, car la visite nécessite un objet et les fonctions de modèle ne sont pas des objets de fonctions; vous ne pouvez pas (encore) passer des noms d'ensemble de surcharge en tant qu'objets en C++.

L'astuce overload est principalement lorsque vous souhaitez distribuer un comportement différent.

Une chose que vous pouvez faire est

template<typename T> 
void printer(T arg) {std::cout << arg; } 

std::visit([](auto&&arg){printer(arg);}, v); 

ou

#define RETURNS(...) \ 
    noexcept(noexcept(__VA_ARGS__)) \ 
    -> decltype(__VA_ARGS__) 

#define OVERLOADS_OF(...) \ 
    [](auto&&...args) \ 
    RETURNS(__VA_ARGS__(decltype(args)(args)...)) \ 
    { return __VA_ARGS__(decltype(args)(args)...); } 

nous obtenons:

template<typename T> 
void printer(T arg) {std::cout << arg; } 

std::visit(OVERLOADS_OF(printer), v); 

qui crée un objet anonyme qui représente l'ensemble de la surcharge de fonctions nommées par le jeton printer.

+0

Vous avez oublié le corps du lambda et vous avez un extra ')' après le premier decltype. – 0x499602D2