2010-12-06 14 views
6

Tengo un typedef boost::variant<int, float, double, long, bool, std::string, boost::posix_time::ptime> variant que utilizo para almacenar diferentes tipos de valores en una estructura. Solo uno del tipo específico se va a almacenar en esa estructura, sin embargo, tengo un vector de estas estructuras que necesito revisar y obtener el tipo real de la variante.genéricamente convertir de impulso :: variante <T> al tipo

Ahora, cuando tengo que hacer la conversión a los tipos de esta variante hago esto:

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); 
        } 

Me preguntaba si hay una manera más genérica que puedo conseguir alrededor de hacer esto escribiendo una función genérica que toma la variante y un tipo T que es el valor de retorno. Pero cuando lo hago todavía tengo que escribir un grupo similar de instrucciones if para dar cuenta de cada tipo de T.

algo así como FromVariant<int>(var);, pero aún tendría que hacerlo para cada tipo en mi variante.

Parece que mi solución genérica no reduce mi código, sino que lo aumenta, lo que obviamente no es el punto. Me preguntaba si alguien tiene una solución más elegante para sacar los diversos tipos de mi variante que es algo genérico, donde puedo simplemente llamar a una función que me da el tipo que quiero volver.

Respuesta

11

En realidad mirando su código un poco más, aquí hay una opción diferente - una vez más basado en el uso de visitante ..

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; 
} 

de usar:

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

Mientras su AddNodeAttribute tiene sobrecargas de todos los tipos, lo anterior debería funcionar ...

+0

yup, 'static_visitor' está ahí para resolver este problema exacto. :) – jalf

+0

quizás trivial para ti ... no para mí, sin embargo ... –

+0

@Tony, cambié mi respuesta: disculpa, no pude dar el código para el otro enfoque (¡está en mi código base en el trabajo!) El enfoque anterior Creo que es más adecuado para su caso, simplemente puede llamar a 'apply_visitor' con todos los campos de su estructura, por ejemplo ... – Nim

2

Cuando estaba usando boost::variant Siempre accedería a los datos contenidos utilizando la técnica de visitante. En mi opinión, esta es una forma muy elegante. No depende de la lógica de conmutación, que es realmente un signo de mal diseño. Vea el documentation.

¡Buena suerte!

+0

¿Conoces más ejemplos? –

+0

Aquí hay un ejemplo que se ve bien después de un vistazo rápido: http://en.highscore.de/cpp/boost/datastructures.html. Desplácese hacia abajo para ver cómo funciona 'boost :: apply_visitor'. –

0

... ¿Qué significa AddNodeAttribute? Básicamente lo mismo para cada tipo, ¿verdad? Si tiene un contenedor de atributos de nodo en alguna parte, básicamente debe ser un contenedor del tipo de variante, ¿verdad?

... ¿Por qué no simplemente reescribir AddNodeAttribute para que sea una sola función que acepte una variante?

+0

Porque necesito el tipo real en la variante, y no la variante. de lo contrario, tendré que hacer la conversión en una etapa posterior de todos modos –

+0

Por favor, explique con más detalle lo que está haciendo con los valores. –

Cuestiones relacionadas