\$\begingroup\$\$\endgroup\$
9This 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);} askedDec 31, 2012 at 11:42
user1131146 account abandoned
7731 gold badge10 silver badges19 bronze badges
- 1\$\begingroup\$This seems not compiling on Visual Studio 2010... anybody tried on VS 2010?\$\endgroup\$Dan Niero– Dan Niero2013-08-21 08:36:22 +00:00CommentedAug 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\$sepp2k– sepp2k2013-08-21 13:07:35 +00:00CommentedAug 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\$user32438– user324382013-11-21 14:54:51 +00:00CommentedNov 21, 2013 at 14:54
- \$\begingroup\$What's your license on this code?\$\endgroup\$user7535– user75352014-04-21 06:34:25 +00:00CommentedApr 21, 2014 at 6:34
- 2\$\begingroup\$@DigitalArchitect: Public domain. You may use it any way you like without attribution.\$\endgroup\$user1131146 account abandoned– user1131146 account abandoned2014-04-21 06:39:33 +00:00CommentedApr 21, 2014 at 6:39
2 Answers2
\$\begingroup\$\$\endgroup\$
0template<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;\$\begingroup\$\$\endgroup\$
~Any(){ if (ptr) delete ptr;}
No need to check for nullptr here becausedelete ignores null pointers.
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.
