2010-06-20 15 views
2
struct A 
    { 
    std::string get_string(); 
    }; 

    struct B 
    { 
    int value; 
    }; 

    typedef boost::variant<A,B> var_types; 
    std::vector<var_types> v; 

    A a; 
    B b; 

    v.push_back(a); 
    v.push_back(b); 

Comment puis-je itérer itération à travers les éléments de v pour avoir accès aux objets a et b?Comment parcourir une séquence de types bornés avec Boost.Variant

Je suis capable de le faire avec boost :: get mais la syntaxe est vraiment lourde .:

std::vector<var_types>:: it = v.begin(); 
while(it != v.end()) 
{ 
    if(A* temp_object = boost::get<A>(&(*it)))  
     std::cout << temp_object->get_string(); 
    ++it; 
} 

J'ai essayé d'utiliser la technique de la visite, mais je n'ai pas trop loin et la le code ne fonctionne pas:

template<typename Type> 
class get_object 
    : public boost::static_visitor<Type> 
{ 
public: 

    Type operator()(Type & i) const 
    { 
    return i; 
    } 

}; 

... 

while(it != v.end()) 
{ 
    A temp_object = boost::apply_visitor(get_object<A>(),*it); 
    ++it; 
} 

EDIT 1

Une solution hackish est:

class get_object 
    : public boost::static_visitor<A> 
{ 
public: 

    A operator()(const A & i) const 
    { 
    return i; 
    } 

    A operator()(const B& i) const 
    { 
    return A(); 
    }   
}; 
+0

Vous voulez itérer à travers l'objet et pour chaque appel d'élément soit fonction X ou Y en fonction si la variante est titulaire d'un A ou B? – GManNickG

+0

Oui, à peu près :) – anno

Répondre

1

Edit:
Si c'est comme Unclebens l'indique, vous pouvez simplement faire ceci:

BOOST_FOREACH(var_types& vt, v) { 
    if (vt.which() == 0) 
     cout << get<A>(vt).get_string() << endl; 
} 

Original:
Le paramètre de modèle pour static_vistor est le type de retour de ses méthodes. Cela signifie que les deux classes doivent partager un type de retour commun pour un seul visiteur. Cela devrait ressembler à ceci:

class ABVisitor : public static_visitor<string> { 
public: 
    string operator()(const A& a) const { 
     return a.get_string(); 
    } 
    string operator()(const B& b) const { 
     return lexical_cast<string>(b.value); 
    } 
}; 

Voici un exemple d'itération utilisant ce visiteur.

BOOST_FOREACH(var_types& vt, v) 
    cout << apply_visitor(ABVisitor(), vt) << endl; 
+0

Mais cela ne produit-il pas toujours quelque chose, alors que dans les tentatives originales, quelque chose était imprimé seulement si l'objet était A? – UncleBens

+0

@UncleBens: vous avez raison. Le corps entier de la boucle for devrait être dans le visiteur cette fois. –

+0

Comme je l'ai dit, je sais comment le faire avec get mais trouver la syntaxe très hostile si je dois l'exposer à travers une interface de classe. – anno

3

Pour autant que je puisse voir, le visiteur est censé faire le travail. Si vous voulez juste obtenir la valeur stockée, puis boost::get - si je ne me trompe pas - est le visiteur pré-fait pour cela.

Exemple:

struct print_if_a : boost::static_visitor<void> 
    { 
    void operator()(A& a) const { std::cout << a.get_string() << '\n'; } //alas, get_string is non-const 
    void operator()(const B&) const {} //does nothing, up to optimizer 
    }; 

Utilisation:

BOOST_FOREACH(var_types& obj, v) { 
    boost::apply_visitor(print_if_a(), obj); 
    } 
+0

Il n'est pas nécessaire de préciser le type de retour de 'boost :: static_visitor' ici, il vaut par défaut' void' si je ne me trompe pas. –

+0

@Matthieu: Oui, vous pouvez aussi écrire 'boost :: static_visitor <>'. – UncleBens