#include <iostream>
#include <array>
#include <limits>
#include <string>
#include <tuple>
#include <vector>
#include <functional>
 
        template<class Tx, class ... Tr> class VariantIndex;
 
                template<class Tx> class VariantIndex<Tx>
                {
                public:
                private:
                };
 
                template<class Tx, class ... Tr> class VariantIndex<Tx, Tx, Tr ...>
                {
                public:
                        static constexpr std::size_t index = 1;
                private:
                };
 
                template<class Tx, class Ty, class ... Tr> class VariantIndex<Tx, Ty, Tr ...>
                {
                public:
                        static constexpr std::size_t index = VariantIndex<Tx, Tr ...>::index + 1;
                private:
                };
 
                template<class ... Tl>
                class Variant
                {
                public:
                        Variant()
                        : m_Type(0)
                        , m_Deleter(nullptr)
                        , m_Data(nullptr)
                        {
                        }
 
                        ~Variant()
                        {
                                if(m_Type && m_Deleter && m_Data)
                                {
                                        m_Deleter(m_Data);
                                }
                                else
                                {
                                        if(m_Type || m_Deleter || m_Data)
                                        {
                                                //LOG << "Type, deleter and data must be set together.";
                                        }
                                }
                        }
 
    		template<class T> static Variant MakeByType(const T& t)
                        {
                                return Make<VariantIndex<T, Tl ...>::index, T>(t);
                        }
                        std::size_t m_Type; ///< Index of type.
                        std::function<void(void*)> m_Deleter; ///< 
                        void *m_Data; ///< Pointer to data.

			template<class T> bool IsType() const
			{
				return m_Type == VariantIndex<T, Tl ...>::index;
			}

			template<class T> const T& GetType() const
			{
				return *reinterpret_cast<const T*>(m_Data);
			}
                private:
			template<std::size_t I, class T> static Variant Make(const T& t)
                        {
                                return Variant(I, [](void *ptr){ std::cout << "Delete type " << I << std::endl; delete reinterpret_cast<T*>(ptr); }, new T(t));
                        }
                        Variant(std::size_t type, std::function<void(void*)>&& deleter, void *data)
                        : m_Type(type)
                        , m_Deleter(std::move(deleter))
                        , m_Data(data)
                        {
                        }
                };
 
        
typedef Variant<int, std::string, char> TestVar;
 
int main(int,char**)
{
    TestVar v = TestVar::MakeByType<int>('a');
    std::cout << v.m_Type << std::endl;
    if(v.IsType<int>())
    {
    	std::cout << "int: " << v.GetType<int>() << std::endl;
    }
    return 0;
}