Friday, September 14, 2007

boost::any

boost::any is a strong concept and a much better replacement to void* to hold any type of data. You can make heterogenous containers using it as well. Let us see how it works in a very simplified way. The idea is to have a template class that can wrap all types and a value associated with that type. Something like this:

template<typename T>
class HoldData
{
    T t;
};

And then having a base class from which this wrapper would derive, so the above becomes adding a constructor that needs the type to be stored in it to be copy constructible:

class BaseHolder
{
    public:
        virtual ~BaseHolder(){}
};

template<typename T>
class HoldData : public BaseHolder
{
    public:
        HoldData(const T& t_) : t(t_){}
    private:
        T t;
};

Now, you would have a class, name it Variant that will take inputs of all types and then has a pointer to this wrapper's base type. So, now you have (including above classes):

class BaseHolder
{
    public:
        virtual ~BaseHolder(){}
};

template<typename T>
class HoldData : public BaseHolder
{
    public:
        HoldData(const T& t_) : t(t_){}
    private:
        T t;
};

class Variant
{
    public:
        template<typename T>
        Variant(const T& t) : data(new HoldData<T>(t)){}
        ~Variant(){delete data;}
    private:
        BaseHolder* data;
};

You construct the corresponding type's wrapper objects and save their pointer into the another class that you call variant, that can hold and help retrieve any data type and does not lose the respective type information. That is actually what boost::any does. Take a look at the code here - boost::any code.

The documentation on it can be found here - boost::any documentation.

4 comments:

AkiRoss' said...

This is really interesting :) I was going to use Boost.variant to do something like void*, but with this post I find boost.any more adapt.
Thanks a lot! And of course for the whole blog, which is really really interesting! Cheers!

abnegator said...

@akiross': boost::variant can be a better choice at times. For the following two reasons: (taken from boost docs)

1. Downcast errors cannot be detected at compile-time. Thus, incorrect usage of downcast constructs will lead to bugs detectable only at run-time.

2. Addition of new concrete types may be ignored. If a new concrete type is added to the hierarchy, existing downcast code will continue to work as-is, wholly ignoring the new type. Consequently, the programmer must manually locate and modify code at numerous locations, which often results in run-time errors that are difficult to find.

boost::variant looks safer in that it is a bounded variant type (meaning it is created/declared for a specific set of types you know you can expect to keep with it) while boost::any would accept almost anything, it can work on unbounded number of types and hence the second reason mentioned ahead. boost::variant also eases visitor pattern application but I think you may find that for boost::any as well.

Which one to choose is basically your call depending on how you plan to solve the problem and if the problem needs a variant type in the first place!?!? :)

Shiva Kumar said...

thanks, Nice info.

But I want to know how we can print the data stored in Variant?

Regards,
Kumar

Joaquim Jesus said...

joaquim

but you include any header files?
because i recive several errors in Dev C++. any advice, please?