这是一个能够容纳任何类型的多态包装。 (大致基于boost::any

,特别是当您要存储异构集合(例如vector<Any>)时,这很有用。

简介

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];


实现

#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;
};


测试

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);
}


评论

这似乎无法在Visual Studio 2010上编译...有人在VS 2010上尝试过吗?

@DanNiero Visual Studio(尤其是2010版本)对C ++ 11的支持不完整。它缺少各种功能,包括模板别名(我认为2012版本也没有),因此您将无法在Visual Studio中编译此代码。

它可以与VS2012一起编译吗?至少不是在我这边。我收到很多编译错误。

您在此代码上的许可证是什么?

@DigitalArchitect:公共领域。您可以随意使用它,而无需注明出处。

#1 楼

template<class T>
using StorageType = typename decay<typename remove_reference<T>::type>::type;


这看起来不必要地复杂:“ decay”已经删除了引用。考虑使用:

template <class T>
using StorageType = typename decay<T>::type; 


#2 楼


~Any()
{
    if (ptr)
        delete ptr;
}



这里不需要检查nullptr,因为delete会忽略空指针。