Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

A C++11 Any Class

Overview

We show a C++11 class Any, that is a polymophic wrapper capable of holding any type. (It is loosely based on boost::any)

In particular this is useful when you want to store a heterogeneous collection. For example vector<Any>.

Synopsis

string s = ...;
int i = ...;

Any a1 = s;
Any a2 = i;

int j = a2; // ok j now equals i

string t = a1; // ok t now equals s

int k = a1; // runtime exception bad_cast

vector<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);
}
share|improve this question
    
This seems not compiling on Visual Studio 2010... anybody tried on VS 2010? –  Dan Niero Aug 21 '13 at 8:36
1  
@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. –  sepp2k Aug 21 '13 at 13:07
    
Does it compile with VS2012? At least, not on my side. I've received a lot of compilation errors. –  Krys Nov 21 '13 at 14:54
    
What's your license on this code? –  Digital Architect 2 days ago
1  
@DigitalArchitect: Public domain. You may use it any way you like without attribution. –  user1131146 account abandoned 2 days ago
show 4 more comments

1 Answer

up vote 6 down vote accepted
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; 
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.