Search code examples
c++unions

generically convert from boost::variant<T> to type


I have a typedef boost::variant<int, float, double, long, bool, std::string, boost::posix_time::ptime> variant which I use to store different types of values in a struct. Only one of the specific type is ever going to be stored in that struct, however I have a vector of these structs which I need to go through and get the actual type out of the variant.

Now when I need to do the conversion the types out of this variant I do this:

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

I wondered if there is a more generic way I can get around doing this by writing a generic function that takes the variant and a type T which is the return value. But when I do that I still have to write similar bunch of if statements to account for each type of T.

so something like FromVariant<int>(var);, but then I would still have to do it for each type in my variant.

So it seems that my generic solution doesn't reduce my code, but increase it, which obviously is not the point. I wondered if anyone has a more elegant solution to getting the various types out of my variant that is somewhat generic, where I can just call a function giving the type I want back?


Solution

  • Actually looking at your code some more, here is a different option - again based on using visitor..

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

    to use:

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

    As long as your AddNodeAttribute has overloads for all types, the above should work...