I often have the requirement to own object instances, while preserving polymorphic behavior (i.e. own the object and hold it by pointer, or reference).
This is usually expressed as a pointer (most of the times, std::unique_ptr), but when the pointer is stored in a std::container, client syntax becomes tricky (with - for example - vector iterators being dereferenced to a pointer - instead of a reference).
To avoid this, I need to implemented a polymorphic wrapper that able to store a heterogeneous collection.
The Basics
I know, many readers say that I know the solution. “void*”
So far in the Standard C++, you had not many options when it comes to holding variable types in a variable. Of course, you could use void*, yet this wasn’t super safe.
Potentially, void* could be wrapped in a class with some type discriminator.
As you see, we have some basic form of the type, but it’s a bit of coding required to make sure “any” is type-safe.
std::any
The C++17 solve this problem with the std::any. It gives you a chance to store anything in an object, and it reports errors (or throw exceptions) when you’d like to access a type that is not active.
The code will output:
It is pretty cool! The STD provide us the polymorphic wrapper capable of holding any type.
std::any is not a template class like std::optional or std::variant.
by default it contains no value, and you can check it via .has_value().
you can reset an any object via .reset().
it works on “decayed” types - so before assignment, initialization, emplacement the type is transformed by std::decay.
when a different type is assigned, then the active type is destroyed.
you can access the value by using std::any_cast, it will throw bad_any_cast if the active type is not T.
you can discover the active type by using .type() that returns std:: type_info of the type.
The only problem with the std::any is that it’s only available from C++17.
Solution
Implement our costume polymorphic wrapper capable of holding any type, based on the std::any and boost::any.
Now as we can see, this is a polymorphic wrapper capable of holding any type. Moreover, this is useful when you want to store a heterogeneous collection, such as vector.
Let’s test it!
My conclusion that try to use the Standard Library rather than rolling a custom implementation. You are avoid code maintance and headache. However the costum any class is a perfect approach when you can not use C++17, but you have to use the polymorphic wrapper.