27
\$\begingroup\$

This is a polymorphic 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, such as 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);
}
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Dec 31, 2012 at 11:42
\$\endgroup\$
9
  • 1
    \$\begingroup\$ This seems not compiling on Visual Studio 2010... anybody tried on VS 2010? \$\endgroup\$ Commented Aug 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\$ Commented Aug 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\$ Commented Nov 21, 2013 at 14:54
  • \$\begingroup\$ What's your license on this code? \$\endgroup\$ Commented Apr 21, 2014 at 6:34
  • 2
    \$\begingroup\$ @DigitalArchitect: Public domain. You may use it any way you like without attribution. \$\endgroup\$ Commented Apr 21, 2014 at 6:39

2 Answers 2

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; 
answered Dec 31, 2012 at 11:53
\$\endgroup\$
0
4
\$\begingroup\$
~Any()
{
 if (ptr)
 delete ptr;
}

No need to check for nullptr here because delete ignores null pointers.

200_success
145k22 gold badges190 silver badges478 bronze badges
answered Apr 17, 2015 at 18:44
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.