This was going to be a FAQ in my book but I think this is better as a blog post.

Let's talk about boost variants. The interesting part of a boost variant is that you must specify the types that it will use. For example:

boost::variant< int, std::string > v;

That's fine - though if you want to store a vector of variants then you must specify the types when defining the vector. For example:

vector<boost::variant< int, std::string > >;

That's not terrible but the issue comes in when you want to get data out of the variant. Without using "visitors" the best you can do is guess or use if statements to check the cast like so:

void times_two( boost::variant< int, std::string > &amp; operand )
{
    if ( int* pi = boost::get<int>( &amp;operand ) )
        *pi *= 2;
    else if ( std::string* pstr = boost::get<std::string>( &amp;operand ) )
        *pstr += *pstr;
}

You could also use .type method on variant to get the type. But all that does is called typeid on *this. typeid is also not the same across platforms so you would have to do something like this:

if (typeid(int) == v.type())

It works but usually not for the stuff you want.

Now onto boost's any. It is what it's name suggests - it will accept any type. However, this has the same drawback as variant - you have to figure out the type on your own - it doesn't provide any built in type hints.

Let's say for example - I have two any objects:

boost::any o1 = 1;
boost::any o2 = "2";
boost::any o3 = o1 + o2;

or more valid code:

boost::any o1 = 1;
boost::any o2 = "2";
boost::any o3 = any_cast<int>(o1) + any_cast<int>(o2);

The compiler says you are not allowed to do that. Casting from char[2] to int is illegal. It kind of makes sense really - are you adding them as strings or as numbers? Well the casting should have made this clear.

With either of them - you have to write extra code to determine if it is a string and convert it to an int.

Now let's talk about ptypes. ptypes is a cross-platform library providing easy to use threading, networking, and replacement types like a string class, a vector replacement, and a variant type.

ptype implements their variant using a union so it <del>doesn't</del> does support (if your class inherits from pt::component you can store it inside of a variant - except you are on your own to determine what the exact class is) any POD type but does compose most of the more common types including for the ability for a variant to turn into an array. It is important to note that - a variant can be changed into ANY datatype and it knows what type it currently is.

So let's take the example from earlier:

variant o1 = 1;
variant o2 = "2";
variant o3 = int(o1) + int(o2);
pout.put(string(o3));

This outputs 3 - similar to any lose typed language like Python. The benefit here is that the casting/conversion is done in the backend so you don't have to worry about if it is a string or int - it just works.

I'm not saying the boost provided types are useless - however - in certain applications you may just want a simpler, looser type, approach.

I have personally done some research into seeing if I can get a variant data type without the use of a union - and so far not much luck without some wild C++ hacking.

My point is that the automatic (intelligent) casting makes quite a difference.