27
\$\begingroup\$

This is a polymorphic wrapper capable of holding any type. (It is loosely based onboost::any)

In particular, this is useful when you want to store a heterogeneous collection, such asvector<Any>.

Synopsis

string s = ...;int i = ...;Any a1 = s;Any a2 = i;int j = a2; // ok j now equals istring t = a1; // ok t now equals sint k = a1; // runtime exception bad_castvector<Any> v;v.push_back("foo");v.push_back(42);const char* s = v[0];int l = v[1];

Implementation

#include <type_traits>#include <utility>#include <typeinfo>#include <string>#include <cassert>using namespace std;template<class T>using StorageType = typename decay<typename remove_reference<T>::type>::type;struct Any{    bool is_null() const { return !ptr; }    bool not_null() const { return ptr; }    template<typename U> Any(U&& value)        : ptr(new Derived<StorageType<U>>(forward<U>(value)))    {    }    template<class U> bool is() const    {        typedef StorageType<U> T;        auto derived = dynamic_cast<Derived<T>*> (ptr);        return derived;    }    template<class U>    StorageType<U>& as()    {        typedef StorageType<U> T;        auto derived = dynamic_cast<Derived<T>*> (ptr);        if (!derived)            throw bad_cast();        return derived->value;    }    template<class U>    operator U()    {        return as<StorageType<U>>();    }    Any()        : ptr(nullptr)    {    }    Any(Any& that)        : ptr(that.clone())    {    }    Any(Any&& that)        : ptr(that.ptr)    {        that.ptr = nullptr;    }    Any(const Any& that)        : ptr(that.clone())    {    }    Any(const Any&& that)        : ptr(that.clone())    {    }    Any& operator=(const Any& a)    {        if (ptr == a.ptr)            return *this;        auto old_ptr = ptr;        ptr = a.clone();        if (old_ptr)            delete old_ptr;        return *this;    }    Any& operator=(Any&& a)    {        if (ptr == a.ptr)            return *this;        swap(ptr, a.ptr);        return *this;    }    ~Any()    {        if (ptr)            delete ptr;    }private:    struct Base    {        virtual ~Base() {}        virtual Base* clone() const = 0;    };    template<typename T>    struct Derived : Base    {        template<typename U> Derived(U&& value) : value(forward<U>(value)) { }        T value;        Base* clone() const { return new Derived<T>(value); }    };    Base* clone() const    {        if (ptr)            return ptr->clone();        else            return nullptr;    }    Base* ptr;};

Test

int main(){    Any n;    assert(n.is_null());    string s1 = "foo";    Any a1 = s1;    assert(a1.not_null());    assert(a1.is<string>());    assert(!a1.is<int>());    Any a2(a1);    assert(a2.not_null());    assert(a2.is<string>());    assert(!a2.is<int>());    string s2 = a2;    assert(s1 == s2);}
200_success's user avatar
200_success
146k22 gold badges191 silver badges481 bronze badges
askedDec 31, 2012 at 11:42
user1131146 account abandoned's user avatar
\$\endgroup\$
9
  • 1
    \$\begingroup\$This seems not compiling on Visual Studio 2010... anybody tried on VS 2010?\$\endgroup\$CommentedAug 21, 2013 at 8:36
  • 2
    \$\begingroup\$@DanNiero The C++11 support in Visual Studio (especially the 2010 version) is incomplete. It lacks various features including template aliases (which, I think, the 2012 version lacks as well), so you won't get this code to compile in Visual Studio.\$\endgroup\$CommentedAug 21, 2013 at 13:07
  • \$\begingroup\$Does it compile with VS2012? At least, not on my side. I've received a lot of compilation errors.\$\endgroup\$CommentedNov 21, 2013 at 14:54
  • \$\begingroup\$What's your license on this code?\$\endgroup\$CommentedApr 21, 2014 at 6:34
  • 2
    \$\begingroup\$@DigitalArchitect: Public domain. You may use it any way you like without attribution.\$\endgroup\$CommentedApr 21, 2014 at 6:39

2 Answers2

15
\$\begingroup\$
template<class T>using StorageType = typename decay<typename remove_reference<T>::type>::type;

This appears unnecessarily complex: 'decay' already removes a reference. Consider using:

template <class T>using StorageType = typename decay<T>::type;
answeredDec 31, 2012 at 11:53
Andrzej's user avatar
\$\endgroup\$
0
4
\$\begingroup\$
~Any(){    if (ptr)        delete ptr;}

No need to check for nullptr here becausedelete ignores null pointers.

200_success's user avatar
200_success
146k22 gold badges191 silver badges481 bronze badges
answeredApr 17, 2015 at 18:44
Pietro Cerutti's user avatar
\$\endgroup\$

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.