6

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?

timrau
  • 22,578
  • 4
  • 51
  • 64
Tony The Lion
  • 61,704
  • 67
  • 242
  • 415

3 Answers3

11

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...

Nim
  • 33,299
  • 2
  • 62
  • 101
  • yup, `static_visitor` is there to solve this exact problem. :) – jalf Dec 06 '10 at 11:37
  • @Tony, changed my answer - sorry I couldn't give out the code for the other approach (it's in my codebase at work!) The above approach I think is more suitable for your case, you can simply call `apply_visitor` with all the fields in your structure for example... – Nim Dec 06 '10 at 11:46
2

When I was using boost::variant I would always access the contained data using visitor technique. In my opinion this is a very elegant way. It does not rely on switch-logic, which is really a sign of bad design. See the documentation.

Good luck!

Daniel Lidström
  • 9,930
  • 1
  • 27
  • 35
0

... What does AddNodeAttribute do? Basically the same thing for each type, right? If you have a container of node attributes somewhere, then it basically needs to be a container of the variant type, right?

... So why not just rewrite AddNodeAttribute to be a single function accepting a variant?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153