2010-12-06 24 views
6

J'ai un typedef boost::variant<int, float, double, long, bool, std::string, boost::posix_time::ptime> variant que j'utilise pour stocker différents types de valeurs dans un struct. Un seul du type spécifique va jamais être stocké dans cette structure, mais j'ai un vecteur de ces structs que j'ai besoin de passer en revue et d'obtenir le type réel de la variante.convertir génériquement de boost :: variant <T> en type

Maintenant, quand je dois faire la conversion des types de cette variante je fais ceci:

variant second = mystruct.variant; 
           if (second.which() == 5) //string 
        { 
         std::string val = boost::get<std::string>(second); 
         modvalue->AddNodeAttribute(key, val); 
        } 
        else if (second.which() == 0) //int 
        { 
         int val = boost::get<int>(second); 
         modvalue->AddNodeAttribute(key, val); 
        } 
        else if (second.which() == 2) //double 
        { 
         double val = boost::get<double>(second); 
         modvalue->AddNodeAttribute(key,val); 
        } 
        else if (second.which() == 1) //float 
        { 
         float val = boost::get<float>(second); 
         modvalue->AddNodeAttribute(key, val); 
        } 
        else if (second.which() == 3) // long 
        { 
         long val = boost::get<long>(second); 
         modvalue->AddNodeAttribute(key, val); 
        } 
        else if (second.which() == 4) // bool 
        { 
         bool val = boost::get<bool>(second); 
         modvalue->AddNodeAttribute(key, val); 
        } 
        else if (second.which() == 6) // posix::time 
        { 
         boost::posix_time::ptime ptm = boost::get<boost::posix_time::ptime>(second); 
         modvalue->AddNodeAttribute(key, ptm); 
        } 

Je me demandais s'il y a une façon plus générique que je peux contourner le faire en écrivant une fonction générique prend la variante et un type T qui est la valeur de retour. Mais quand je fais cela, je dois encore écrire un tas d'instructions if pour tenir compte de chaque type de T.

donc quelque chose comme FromVariant<int>(var);, mais alors je devrais encore le faire pour chaque type dans ma variante.

Il semble donc que ma solution générique ne réduit pas mon code, mais l'augmente, ce qui n'est évidemment pas le cas. Je me demandais si quelqu'un avait une solution plus élégante pour obtenir les différents types de ma variante qui est quelque peu générique, où je peux simplement appeler une fonction donnant le type que je veux en arrière?

Répondre

11

regardant fait votre code un peu plus, voici une autre option - encore une fois basée sur l'utilisation de visiteurs ..

struct add_node_visitor : boost::static_visitor<> 
{ 
    add_node_visitor(<type of modvalue> & node, <type of key> & key) : _node(node), _key(key) {} 

    template <typename _Item> 
    void operator()(_Item const& item) 
    { 
    node->AddNodeAttribute(_key, item); 
    } 

    <type of modvalue> & _node; 
    <type of key> & _key; 
} 

à utiliser:

boost::apply_visitor (add_node_visitor(modmodvalue, key), mystruct.variant); 

Tant que votre AddNodeAttribute a pour surcharge tous les types, ce qui précède devrait fonctionner ...

+0

yup, 'static_visitor' est là pour résoudre ce problème. :) – jalf

+0

peut-être trivial à vous ... pas à moi cependant ... –

+0

@Tony, a changé ma réponse - désolé je ne pouvais pas donner le code pour l'autre approche (c'est dans mon code de base au travail!) L'approche ci-dessus Je pense que c'est plus approprié pour votre cas, vous pouvez simplement appeler 'apply_visitor' avec tous les champs de votre structure par exemple ... – Nim

2

Lorsque j'utilisais boost::variant, j'accédais toujours aux données contenues en utilisant la technique du visiteur. À mon avis, c'est un moyen très élégant. Il ne repose pas sur la logique de commutation, ce qui est vraiment un signe de mauvaise conception. Voir le documentation.

Bonne chance!

+0

connaissez-vous d'autres exemples? –

+0

Voici un exemple qui a l'air agréable après un rapide coup d'œil: http://en.highscore.de/cpp/boost/datastructures.html. Faites défiler vers le bas pour voir comment 'boost :: apply_visitor' fonctionne. –

0

... Que fait AddNodeAttribute? Fondamentalement la même chose pour chaque type, non? Si vous avez un conteneur d'attributs de noeud quelque part, alors il doit fondamentalement être un conteneur du type variant, non? ... pourquoi ne pas simplement réécrire AddNodeAttribute pour être une seule fonction acceptant une variante?

+0

Parce que j'ai besoin du type réel dans la variante, et non de la variante. sinon je devrai faire la conversion à un stade ultérieur de toute façon –

+0

Veuillez expliquer plus en détail ce que vous faites avec les valeurs. –