C++17组件:variant简单实现示例

#include 
#include 
#include 
#include 
#include 
#include 
#include
#include
#include
#include"functiona_traits.h"

namespace ts
{
    template<size_t I, typename...Types>
    struct type_list
    {
        using type = std::tuple_element_t<I, std::tuple<Types...>>;
    };
    template<size_t I, typename...Types>
    using type_list_t = typename type_list<I, Types...>::type;

    template<typename T, typename...Args>
    struct Integermax :std::integral_constant<int, (sizeof(T) > Integermax<Args...>::value ? sizeof(T) : Integermax<Args...>::value) >{ };
    template<typename T>
    struct Integermax<T> :std::integral_constant<int, sizeof(T) > {};

    template<typename T,typename... Args>
    struct MaxAlign :std::integral_constant<int, (alignof(T) > MaxAlign<Args...>::value ? alignof(T) : MaxAlign<Args...>::value) > {};
    template<typename T>
    struct MaxAlign<T> :std::integral_constant<int, alignof(T) > {};

    template<typename T, typename ...List>
    struct contains :std::true_type {};

    template<typename T, typename head, typename ...rest>
    struct contains<T, head, rest...> :std::conditional_t<std::is_same_v<T, head>, std::true_type, typename contains<T, rest...>::type> {};

    template<typename T>
    struct contains<T> :std::false_type {};

    template <class... Types>
    struct Variant
    {
        static const int datasize = Integermax<Types...>::value;
        static const int alignsize = MaxAlign<Types...>::value;
        using data_t= std::aligned_storage_t<datasize, alignsize>;

        template<typename T,typename...Args>
        struct helper
        {
            template<typename U>
            static void init(U&& arg, data_t* data, std::type_index* ptid)
            {
                if constexpr (std::is_constructible_v<T, U>)
                {
                    *ptid = std::type_index(typeid(T));
                    new(data)T(arg);
                }      
                else
                    helper<Args...>::init(std::forward<U>(arg), data, ptid);            
            }

            static void copy(std::type_index id,const data_t* other, data_t* dest)
            {
                if (id == std::type_index(typeid(T)))
                    new(dest) T(*reinterpret_cast<const T*>(other));
                else
                    helper<Args...>::copy(id, other, dest);
            }
            static void move(std::type_index id, data_t* other, data_t* dest)
            {
                if (id == std::type_index(typeid(T)))             
                    new(dest)T(std::move(*reinterpret_cast<T*>(other)));                
                else           
                    helper<Args...>::move(id, other, dest);  
            }

            static void destroy(std::type_index id, data_t* data)
            {
                if (id == std::type_index(typeid(T)))
                    reinterpret_cast<T*>(data)->~T();
                else
                    helper<Args...>::destroy(id, data);
            }

            static int index(std::type_index id,size_t index)
            {
                if (id == std::type_index(typeid(T)))
                    return index;
                else
                    return  helper<Args...>::index(id, index+1);
            }
        };

        template<typename T>
        struct helper<T>
        {
            template<typename U>
            static void init(U&& arg, data_t* data, std::type_index* ptid)
            {
                if constexpr (std::is_constructible_v<T, U>)
                {
                    *ptid = std::type_index(typeid(T));
                    new(data)T(arg);
                }
                else
                    throw std::exception{};
            }

            static void copy(std::type_index id, const data_t* other, data_t* dest)
            {
                if (id == std::type_index(typeid(T)))
                    new(dest)T(*reinterpret_cast<const T*>(other));
                else
                    throw std::exception{};
            }
            static void move(std::type_index id, data_t* other, data_t* dest)
            {
                if (id == std::type_index(typeid(T)))
                    new(dest)T(std::move(*reinterpret_cast<T*>(other)));
                else
                    throw std::exception{};
            }

            static void destroy(std::type_index id, data_t* data)
            {
                if (id == std::type_index(typeid(T)))
                    reinterpret_cast<T*>(data)->~T();
                else
                    throw std::exception{};
            }

            static int index(std::type_index id, size_t index)
            {
                if (id == std::type_index(typeid(T)))
                    return index;
                else
                    throw std::exception{};
            }
        };


        constexpr Variant(const Variant& other):m_tpIndex(other.m_tpIndex)
        {
            helper<Types...>::copy(other.m_tpIndex, &other.m_data, &m_data);
        }

        constexpr Variant(Variant&& other):m_tpIndex(other.m_tpIndex)
        {
            helper<Types...>::move(other.m_tpIndex, &other.m_data, &m_data);
        }

        template< typename U,std::enable_if_t<std::negation_v<std::is_same<Variant,std::_Remove_cvref_t<U>>>,int> =0 >
        constexpr Variant(U&& t):m_tpIndex(std::type_index(typeid(void)))
        {
            helper<Types...>::init(std::forward<U>(t), &m_data, &m_tpIndex);
        }

        constexpr Variant& operator=(const Variant& other) 
        {
            if (this != &other)
            {        
                helper<Types...>::destroy(m_tpIndex, &m_data);
                helper<Types...>::copy(other.m_tpIndex, &other.m_data, &m_data);
                m_tpIndex = other.m_tpIndex;
            }
            return *this;
        }
        constexpr Variant& operator=(Variant&& other)
        {     
            if (this != &other)
            {  
                helper<Types...>::destroy(m_tpIndex, &m_data);
                helper<Types...>::move(other.m_tpIndex, &other.m_data, &m_data);
                m_tpIndex = other.m_tpIndex;
            }
            return *this;
        }
        template< typename U, std::enable_if_t<std::negation_v<std::is_same<Variant, std::_Remove_cvref_t<U>>>, int> = 0 >
        constexpr Variant& operator=(U&& t) 
        {
            helper<Types...>::destroy(m_tpIndex, &m_data);
            helper<Types...>::init(std::forward<U>(t), &m_data, &m_tpIndex);
            return *this;
        }

        //是否是当前类型状态
        template<typename U>
        constexpr bool is()
        {
            if(m_tpIndex == std::type_index(typeid(U)))
                return true;
                return false;
        }
        //获取类型状态的值,如果是U当前类型状态
        template<typename U>
        constexpr decltype(auto) get()
        {
            using type = std::decay_t<U>;
            if (!is<type>())
            {
                std::cout << typeid(type).name() << "Not define!" << std::endl;
                throw std::bad_cast();
            }
          return   reinterpret_cast<type&>(m_data);
        }
        //根据模板参数列表索引取当前类型状态
        template<size_t I>
        constexpr decltype(auto) get()
        {
            using type = type_list_t<I, Types...>;
            return get<type>();
        }

        //获取当前类型状态对应的模板参数表索引
        constexpr  size_t index()
        {
            return helper<Types...>::index(m_tpIndex, 0);
        }
        //U是否是模板参数表的类型状态
        template<typename U>
        bool has_type()
        {
            return  contains<U, Types...>::value;
        }

        template<typename U>
        int getindexof()
        {
            if (has_type<U>())
            {
                using type = std::decay_t<U>;
                auto tid = std::type_index(typeid(type));
                return helper<Types...>::index(tid, 0);
            }    
            return -1;
        }
        //此访问者接口不同于C++标准std::visit;只能观察当前Variant本身,观察者符合要求才会调用到,否则不调用
        template<typename F>
        void visit(F&& f)
        {
            using T = std::decay_t<typename function_traits<std::decay_t<F>>::template ArgN_t<0>>;

            if (is<T>())
                f(get<T>());
        }

        template<typename F,typename...Rest>
        void visit(F&& f, Rest&&...rest)
        {
            using T = std::decay_t<typename function_traits<std::decay_t<F>>::template ArgN_t<0>>;

            if (is<T>())
                visit(std::forward<F>(f));
            else
                visit(std::forward<Rest>(rest)...);
        }

        std::type_index m_tpIndex;
        data_t m_data;
    };

    template< std::size_t I, typename... Types >
    constexpr decltype(auto) Get(Variant<Types...>& v)
    {
       return v.get<I>();
    }

    void Print1(const std::string& s)
    {
        std::cout << s << std::endl;
    }
    void Print(int s)
    {
        std::cout << s << std::endl;
    }
    void test()
    {
        Variant<int, std::string, char*> v("123");
        std::cout << v.getindexof<char*>() << std::endl;
        std::cout << v.has_type<int>() << std::endl;
        std::cout << v.get<std::string>() << std::endl;

   //     std::cout << v.get() << std::endl;

        Variant<int, std::string, char*> v1(v);
        std::cout << v1.getindexof<char*>() << std::endl;
        std::cout << v1.has_type<int>() << std::endl;
        std::cout << v1.get<std::string>() << std::endl;
 //       std::cout << v1.get() << std::endl;

        v1 = 888;
        std::cout << v1.getindexof<char*>() << std::endl;
        std::cout << v1.has_type<int>() << std::endl;
        std::cout << v1.get<int>() << std::endl;


        v1 = v;
        std::cout << v1.getindexof<char*>() << std::endl;
        std::cout << v1.has_type<int>() << std::endl;
        std::cout << v1.get<std::string>() << std::endl;
        std::cout << Get<1>(v1) << std::endl;

        v1.visit(Print, Print1);
       // std::cout << v1.get<0>() << std::endl;
    }
}
int main() {

    ts::test();
    return 0;
}

function_traits

你可能感兴趣的:(c++,开发语言)