#include <iostream>
#include <memory>
class any_ptr
{
struct WrapperBase
{
virtual ~WrapperBase(){}
};
template<typename T>
struct Wrapper : WrapperBase, T
{
template<typename ... Args>
Wrapper( Args&&... args ):
T( std::forward<Args>(args)... ) {}
};
std::unique_ptr<WrapperBase> mPtr;
any_ptr( std::unique_ptr<WrapperBase> ptr ):
mPtr{ std::move(ptr) } {}
public:
template< typename T >
explicit operator T*()
{
return dynamic_cast<T*>(mPtr.get());
}
template< typename T >
explicit operator T const*() const
{
return dynamic_cast<T*>(mPtr.get());
}
template<typename T>
friend any_ptr make_any_ptr( T&& t )
{
return std::unique_ptr<WrapperBase>{ new Wrapper<T>{ std::forward<T>(t) } };
}
template< typename T,
typename ... Args >
friend any_ptr make_any_ptr( Args&&... args )
{
return std::unique_ptr<WrapperBase>{ new Wrapper<T>{ std::forward<Args>(args)... } };
}
};
////////////////////////////////////////////////////////////////////////////////
template <class T>
bool inspect(any_ptr& p, void (&fun)(T))
{
using actual_t = typename std::remove_reference<T>::type;
if( actual_t* t = static_cast<actual_t*>(p) )
fun(*t);
return false;
}
////////////////////////////////////////////////////////////////////////////////
class printable
{
public:
virtual void print() const = 0;
};
////////////////////////////////////////////////////////////////////////////////
#include <string>
using namespace std;
class foo : public printable
{
public:
foo(string const& s) : m_s(s) {}
virtual void print() const
{
cout << "foo: " << m_s << "\n";
}
private:
string m_s;
};
class bar : public printable
{
public:
bar(int i) : m_i(i) {}
virtual void print() const
{
cout << "bar: " << m_i << "\n";
}
private:
int m_i;
};
////////////////////////////////////////////////////////////////////////////////
void print_printable(printable& p)
{
p.print();
}
////////////////////////////////////////////////////////////////////////////////
int main()
{
auto f = make_any_ptr(foo("foo"));
auto b = make_any_ptr(bar(42));
inspect(f, print_printable);
inspect(b, print_printable);
}