#include <iostream>
#include <memory>

template<typename T>
using require_scalar = typename std::enable_if<std::is_arithmetic<T>::value>::type;

template<typename T>
using require_not_scalar = typename std::enable_if<not std::is_arithmetic<T>::value>::type;

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

    template< typename T >
    struct ScalarWrapper : WrapperBase
    {
    	T scalar;

    	template<typename ... Args>
    	ScalarWrapper( Args&&... args ):
    		scalar( std::forward<Args>(args)... ) {}
    };

    std::unique_ptr<WrapperBase> mPtr;

    any_ptr( std::unique_ptr<WrapperBase> ptr ):
        mPtr{ std::move(ptr) } {}

    template< typename T >
    T* _access( std::false_type ) const
    {
        return dynamic_cast<T*>(mPtr.get());
    }

    template< typename T >
    T* _access( std::true_type ) const
    {
    	auto ptr = dynamic_cast<ScalarWrapper<T>*>(mPtr.get());
        return ptr ? &ptr->scalar : nullptr ;
    }

    template< typename T,
              typename ... Args >
    static any_ptr _make_any_ptr( std::false_type, Args&&... args )
    {
        return std::unique_ptr<WrapperBase>{ new Wrapper<T>{ std::forward<Args>(args)... } };
    }

    template< typename T >
    static any_ptr _make_any_ptr( std::true_type, T arg )
    {
        return std::unique_ptr<WrapperBase>{ new ScalarWrapper<T>{arg} };
    }

public:

	template< typename T >
	T* access()
	{ return _access<T>( typename std::is_arithmetic<T>::type{} ); }

	template< typename T >
	T const* access() const
	{ return _access<T>( typename std::is_arithmetic<T>::type{} ); }

    template< typename T,
              typename ... Args >
    friend any_ptr make_any_ptr( Args&&... args )
    {
        return _make_any_ptr<T>( typename std::is_arithmetic<T>::type{}, std::forward<Args>(args)... );
    }
};

////////////////////////////////////////////////////////////////////////////////

template <class T>
void inspect(any_ptr& p, void (&fun)(T))
{
    using actual_t = typename std::remove_reference<T>::type;

    if( auto t = p.access<actual_t>() )
        fun(*t);
}

////////////////////////////////////////////////////////////////////////////////

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);
    auto c = make_any_ptr<int>(42);

    inspect(f, print_printable);
    inspect(b, print_printable);

    auto ptr = c.access<int>();
    std::cout << *ptr;
}
