Skip to content

Instantly share code, notes, and snippets.

@shoooe
Last active July 5, 2021 02:19
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save shoooe/9202235 to your computer and use it in GitHub Desktop.
Save shoooe/9202235 to your computer and use it in GitHub Desktop.
A simple implementation of Boost's any, as an exercise.
#pragma once
#include <exception>
#include <memory>
#include <typeinfo>
#include <type_traits>
class any;
template<class Type> Type any_cast(any&);
template<class Type> Type any_cast(const any&);
template<class Type> Type* any_cast(any*);
template<class Type> const Type* any_cast(const any*);
struct bad_any_cast : public std::bad_cast {};
class any {
public:
template<class Type> friend
Type any_cast(any&);
template<class Type>
friend Type any_cast(const any&);
template<class Type>
friend Type* any_cast(any*);
template<class Type>
friend const Type* any_cast(const any*);
any()
: ptr(nullptr)
{}
any(any&& x)
: ptr(std::move(x.ptr))
{}
any(const any& x) {
if (x.ptr)
ptr = x.ptr->clone();
}
template<class Type> any(const Type& x)
: ptr(new concrete<typename std::decay<const Type>::type>(x))
{}
any& operator=(any&& rhs) {
ptr = std::move(rhs.ptr);
return (*this);
}
any& operator=(const any& rhs) {
ptr = std::move(any(rhs).ptr);
return (*this);
}
template<class T> any& operator=(T&& x) {
ptr.reset(new concrete<typename std::decay<T>::type>(typename std::decay<T>::type(x)));
return (*this);
}
template<class T> any& operator=(const T& x) {
ptr.reset(new concrete<typename std::decay<T>::type>(typename std::decay<T>::type(x)));
return (*this);
}
void clear() {
ptr.reset(nullptr);
}
bool empty() const {
return ptr == nullptr;
}
const std::type_info& type() const {
return (!empty())
? ptr->type()
: typeid(void);
}
private:
struct placeholder {
virtual std::unique_ptr<placeholder> clone() const = 0;
virtual const std::type_info& type() const = 0;
virtual ~placeholder() {}
};
template<class T>
struct concrete : public placeholder {
concrete(T&& x)
: value(std::move(x))
{}
concrete(const T& x)
: value(x)
{}
virtual std::unique_ptr<placeholder> clone() const override {
return std::unique_ptr<placeholder>(new concrete<T>(value));
}
virtual const std::type_info& type() const override {
return typeid(T);
}
T value;
};
std::unique_ptr<placeholder> ptr;
};
template<class Type>
Type any_cast(any& val) {
if (val.ptr->type() != typeid(Type))
throw bad_any_cast();
return static_cast<any::concrete<Type>*>(val.ptr.get())->value;
}
template<class Type>
Type any_cast(const any& val) {
return any_cast<Type>(any(val));
}
template<class Type>
Type* any_cast(any* ptr) {
return dynamic_cast<Type*>(ptr->ptr.get());
}
template<class Type>
const Type* any_cast(const any* ptr) {
return dynamic_cast<const Type*>(ptr->ptr.get());
}
Copy link

ghost commented Sep 18, 2016

nice :)

@kubatrt
Copy link

kubatrt commented Oct 13, 2016

gj!

@aorandexiaohai
Copy link

Thanks!

@RobinYou19
Copy link

GG !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment