2010-01-25 4 views
2

J'ai essayé la lecture:Comment implémenter un modèle Variant basique (& un visiteur sur le Variant) en C++?

http://www.boost.org/doc/libs/1_41_0/boost/variant.hpp 


http://www.codeproject.com/KB/cpp/TTLTyplist.aspx 


and chapter 3 of "Modern C++ Design" 

mais ne comprennent toujours pas comment les variantes sont mises en œuvre. Quelqu'un peut-il coller un court exemple de la façon de définir quelque chose comme:

class Foo { 
    void process(Type1) { ... }; 
    void process(Type2) { ... }; 
}; 


Variant<Type1, Type2> v; 

v.somethingToSetupType1 ...; 

somethingToTrigger process(Type1); 

v.somethingToSetupType2 ...; 

somethingToTrigger process(Type2); 

Merci!

+0

Demandez-vous comment implémenter des variantes, ou comment utiliser la mise en œuvre de coup de pouce? – Anne

+0

Il est clair qu'il veut savoir comment implémenter des variantes. –

+0

Je veux savoir comment _implement_; pas comment utiliser _use_ variantes. – anon

Répondre

2

Si je devais définir un objet variant, je serais probablement commencer par ce qui suit:

template<typename Type1, typename Type2> 
class VariantVisitor; 

template<typename Type1, typename Type2> 
class Variant 
{ 
public: 
    friend class VariantVisitor<Type1, Type2>; 
    Variant(); 
    Variant(Type1); 
    Variant(Type2); 
    // + appropriate operators = 
    ~Variant(); // deal with memory management 

private: 
    int type; // 0 for invalid data, 1 for Type1, 2 for Type2 
    void* data; 
}; 

template<typename Visitor, typename Type1, typename Type2> 
class VariantVisitor 
{ 
    private: 
    Visitor _customVisitor; 
    public: 
    void doVisit(Variant<Type1, Type2>& v) 
    { 
     if(v.type == 1) 
     { 
      _customVisitor(*(Type1*)(v.data)); 
     } 
     else if(v.type == 2) 
     { 
      _customVisitor(*(Type2*)(v.data)); 
     } 
     else 
     { 
     // deal with empty variant 
     } 
    } 
}; 
template<typename Visitor, typename Type1, typename Type2> 
void visit(Visitor visitor, Variant<Type1, Type2> v) 
{ 
    VariantVisitor<Visitor, Type1, Type2>(visitor).doVisit(v); 
} 

puis utilisez MPL vectors pour faire le travail d'approche pour plus que deux types différents.

En fin de compte, vous pourriez écrire quelque chose comme ceci:

Variant<Type1, Type2> v; 
class MyVisitor 
{ 
    public: 
    operator()(Type1); 
    operator()(Type2); 
}; 

MyVisitor visitor; 
v = Type1(); 
visit(visitor, v); 
v = Type2(); 
visit(visitor, v); 

NB: il n'y a aucune chance de ce code compile, mais cela décrit les idées j'utiliser.

+0

Je doute que ce soit quelque chose comme Boost.Variant, cependant. Par exemple, sizeof (variant ) n'est-il pas dépendant du plus grand des types - ce qui indique que les valeurs ne sont pas stockées comme 'void * '? - Malheureusement, la source est trop longue et compliquée pour que je la lise (il faut probablement combattre le compilateur pour chaque petit pas vers l'objectif, donc je suis reconnaissant de pouvoir utiliser le travail des autres si j'en ai besoin :)) – UncleBens

+1

Je suis complètement d'accord. Je n'utiliserais jamais une version personnelle des variantes. Boost.Variant fonctionne bien et je n'ai pas vraiment besoin de savoir comment. J'expliquais simplement comment cela pouvait être fait. –

1

Je pense que vous demandez comment utiliser variantes, pas comment les mettre en œuvre . Vous pouvez vouloir regarder le boost documentation on variants; ce sera beaucoup plus utile que de regarder le fichier d'en-tête.

Ensuite, votre exemple pourrait ressembler à ceci:

class v_visitor : public boost::static_visitor 
{ 
public: 
    void operator()(Type1 &t) const {...} 
    void operator()(Type2 &t) const {...} 
}; 

v = Type1(...); 
boost::apply_visitor(v_visitor(), v); 
Questions connexes