2010-06-08 24 views
4

Hy là,Iterator pour boost :: variante

J'essaie d'adapter un code existant à boost :: variant. L'idée est d'utiliser boost :: variant pour un vecteur hétérogène. Le problème est que le reste du code utilise des itérateurs pour accéder aux éléments du vecteur. Est-il possible d'utiliser boost :: variant avec des itérateurs?

J'ai essayé

typedef boost::variant<Foo, Bar> Variant; 
std::vector<Variant> bag; 
std::vector<Variant>::iterator it; 
for(it= bag.begin(); it != bag.end(); ++it){ 

cout<<(*it)<<endl; 
} 

Mais cela n'a pas fonctionné.

EDIT: Merci pour votre aide! Mais dans ma conception, j'ai besoin d'obtenir un élément de la liste et le passer autour d'autres parties du code (et cela peut être désagréable, car j'utilise GSL). L'idée d'utiliser un itérateur est que je peux passer l'itérateur à une fonction, et la fonction fonctionnera sur les données de retour de cet élément spécifique. Je ne vois pas comment faire ça en utilisant for_each. Je dois faire quelque chose de similaire à cela:

for(it=list.begin(); it!=list.end();++it) { 
    for(it_2=list.begin(); it_2!=list.end();++it_2) { 

    if(it->property() != it_2->property()) { 

     result = operate(it,it_2); 

     } 
    } 

} 

Merci!

Répondre

8

Bien sûr, il y a. Le déréférencement des itérateurs produira naturellement une référence boost::variant<...> ou une référence const.

Cependant, cela signifie que le reste du code doit être compatible avec les variantes. Et notamment utiliser le boost::static_visitor pour exécuter des opérations sur les variantes.

EDIT:

facile!

struct Printer: boost::static_visitor<> 
{ 
    template <class T> 
    void operator()(T const& t) const { std::cout << t << std::endl; } 
}; 

std::for_each(bag.begin(), bag.end(), boost::apply_visitor(Printer()); 

Notez que l'écriture d'un visiteur génère automatiquement un prédicat pour les algorithmes STL, miam!

Maintenant, pour la question de la valeur de retour:

class WithReturn: boost::static_visitor<> 
{ 
public: 
    WithReturn(int& result): mResult(result) {} 

    void operator()(Foo const& f) const { mResult += f.suprise(); } 
    void operator()(Bar const& b) const { mResult += b.another(); } 

private: 
    int& mResult; 
}; 


int result; 
std::for_each(bag.begin(), bag.end(), boost::apply_visitor(WithReturn(result))); 

EDIT 2:

Il est facile, mais en effet besoin d'un peu d'entraînement :)

Tout d'abord, on remarque il y a 2 opérations différentes: != et operate

struct PropertyCompare: boost::static_visitor<bool> 
{ 
    template <class T, class U> 
    bool operator()(T const& lhs, U const& rhs) 
    { 
    return lhs.property() == rhs.property(); 
    } 
}; 

struct Operate: boost::static_visitor<result_type> 
{ 
    result_type operator()(Foo const& lhs, Foo const& rhs); 
    result_type operator()(Foo const& lhs, Bar const& rhs); 
    result_type operator()(Bar const& lhs, Bar const& rhs); 
    result_type operator()(Bar const& lhs, Foo const& rhs); 
}; 

for(it=list.begin(); it!=list.end();++it) { 
    for(it_2=list.begin(); it_2!=list.end();++it_2) { 

    if(!boost::apply_visitor(PropertyCompare(), *it, *it_2)) { 

     result = boost::apply_visitor(Operate(), *it, *it_2)); 

    } 

    } 
} 

Pour chacun n'est pas si bon ici, à cause de cela if. Cela fonctionnerait si vous pouviez en quelque sorte factoriser le if en operate cependant.

Notez également que je ne passe pas les itérateurs mais les références.

+0

Le boost :: static_visitor est bon pour fonctionner sur les éléments, mais ne fonctionne pas lorsque la classe doit retourner des données. J'ai essayé d'utiliser des itérateurs pour boost :: ptr_vector >, mais quelque chose comme ça n'a pas fonctionné: typedef boost :: variant Variante; std :: vecteur sac; std :: vecteur :: iterator it; pour (it = bag.begin(); it! = Sac.fin(); ++ it) { cout << (* it) << endl; } – Ivan

+0

Modifié l'entrée pour illustrer l'utilisation. –

+0

Merci beaucoup. J'essaie toujours d'adapter le concept à mon code existant sans trop changer. Nouvelle modification ci-dessus. – Ivan