2017-09-27 11 views
1

Pour une raison quelconque, en utilisant la variante de boost (je sais qu'il ya une C++ 17 la version, je suis fournir rétrocompatibilité ici, et en plus C++ 17 ne sont pas entièrement pris en charge par clang ++ encore) conduit à un comportement étrange quand en utilisant le paradigme du visiteur:Comment faire pour contourner apply_visitor variante ne supporte pas 3 args?

2 arguments, travaille

#include <iostream> 
#include <boost/variant.hpp> 

using boost::variant; 

typedef boost::variant<double, std::string> term_t; 

class plus_visitor : public boost::static_visitor<term_t> { 
public: 
    term_t operator()(double lhs, double rhs) const{ 
     return {lhs + rhs}; 
    } 
    term_t operator()(double lhs, std::string rhs) const{ 
     return {lhs + std::stoi(rhs)}; 
    } 
    term_t operator()(std::string lhs, int rhs) const{ 
     return operator()(rhs, lhs); 
    } 
    term_t operator()(std::string lhs, std::string rhs) const{ 
     return std::stoi(lhs) + std::stoi(rhs); 
    } 
}; 

int main(){ 
    // term_t lhs {3.0}; 
    term_t rhs {"10"}; 
    term_t lhs {"3"}; 
    term_t res = boost::apply_visitor(plus_visitor(), lhs, rhs); 
    std::cout << res << std::endl; 
    return 0; 
} 

Il produit 13 comme prévu.

3 arguments, explose
#include <iostream> 
#include <boost/variant.hpp> 

using boost::variant; 

typedef boost::variant<double, std::string> term_t; 

class plus_visitor : public boost::static_visitor<term_t> { 
public: 
    term_t operator()(double lhs, double rhs, double x) const{ 
     return {lhs + rhs + x}; 
    } 
    term_t operator()(double lhs, std::string rhs, double x) const{ 
     return {lhs + std::stoi(rhs) + x}; 
    } 
    term_t operator()(std::string lhs, double rhs, double x) const{ 
     return operator()(rhs, lhs, x); 
    } 
    term_t operator()(std::string lhs, std::string rhs, double x) const{ 
     return std::stoi(lhs) + std::stoi(rhs) + x; 
    } 
}; 

int main(){ 
    term_t rhs {"10"}; 
    term_t lhs {"3"}; 
    term_t x {3.0}; 
    term_t res = boost::apply_visitor(plus_visitor(), lhs, rhs, x); 
    std::cout << res << std::endl; 
    return 0; 
} 

Quelle est l'affaire ici? Est-ce que apply_visitor ne fonctionne que pour 2 arguments?

Diagnostic

je regardais à la documentation et a constaté que:

http://www.boost.org/doc/libs/1_36_0/doc/html/boost/apply_visitor.html

apply_visitor ne fonctionne que pour les arguments binaires ou arguments unaire! C'est nul! Comment puis-je contourner cela et en fournir un troisième sans être complètement moche dans la syntaxe? Y a-t-il une autre fonction de bibliothèque boost qui permet plus d'entrées? Pourquoi la bibliothèque boost n'utiliser des modèles variadique pour permettre de taille apply_visitor arbitraires fonctions?

+0

BTW, vous avez oublié beaucoup de surcharges (ceux où 3e paramètre est 'std :: string') – Jarod42

+0

@ Jarod42 Je sais. J'essaie juste de prouver un point ici – OneRaynyDay

+0

Eh bien, point prouvé. Si vous voulez utiliser boost, vous devrez gérer la limitation. Remplacez-les par une structure unique contenant autant de valeurs que vous le souhaitez. –

Répondre

2

Vous regardez la documentation pour Boost 1,36, ce qui était released in 2008. Si vous regardez le documentation for the current release, il énumère les surcharges suivantes apply_visitor

template<typename MultiVisitor, typename Variant1, typename Variant2, 
     typename Variant3> 
    typename MultiVisitor::result_type OR decltype(auto) 
    apply_visitor(MultiVisitor & visitor, Variant1 & operand1, 
       Variant2 & operand2, Variant3 & operand3, ... other_operands); 
template<typename MultiVisitor, typename Variant1, typename Variant2, 
     typename Variant3> 
    typename MultiVisitor::result_type OR decltype(auto) 
    apply_visitor(const MultiVisitor & visitor, Variant1 & operand1, 
       Variant2 & operand2, Variant3 & operand3, ... other_operands); 

La documentation indique également

Surcharges acceptant trois opérandes ou plus invoquer l'opérateur d'appel de fonction du visiteur donné sur le contenu du opérandes variants donnés. ... Ces fonctions sont en fait définies dans un en-tête boost/variant/multivisitors.hpp ... cet en-tête doit être inclus manuellement si les visiteurs sont multiples destinés à une utilisation.

Alors assurez-vous que vous utilisez un récent communiqué de Boost, inclure l'en-tête pertinent, définir les operator() manquantes pour l'surcharge exemple 3 argument et votre code devrait compiler.

+0

Got it. Je vous remercie! J'aimerais qu'ils puissent rendre cela un peu plus visible. En outre, il est extrêmement difficile de lire les messages d'erreur dans cette bibliothèque boost. :( – OneRaynyDay

+0

@OneRaynyDay Les recherches Google affichent rarement la dernière version de Boost, mais si vous regardez une ancienne documentation, il y aura une boîte jaune en haut qui indique que vous ne regardez pas la dernière version et que vous avez un lien pour les derniers docs (bien que ce lien soit cassé dans certains cas :)) – Praetorian