How to build this c++ typelist into a variant?

前端 未结 2 514
南笙
南笙 2021-01-26 04:53

Here,

how do I fix this c++ typelist template compile error?

we built a typelist, using the code from modern c++ design.

Question is now -- how do I take

相关标签:
2条回答
  • 2021-01-26 05:09
    /*
     * variant_modern.hpp
     *
     *  Created on: Jun 4, 2010
     *      Author: vvenedik
     */
    
    #ifndef _VARIANT_MODERN_HPP_
    #define _VARIANT_MODERN_HPP_
    
    struct NullType {} ;
    template <class T, class U>
    struct TypeList
    {
        typedef T Head;
        typedef U Tail;
    };
    
    #define TYPELIST_1(T1) TypeList<T1, NullType> 
    #define TYPELIST_2(T1, T2) TypeList<T1, TYPELIST_1(T2) > 
    #define TYPELIST_3(T1, T2, T3) TypeList<T1, TYPELIST_2(T2, T3) > 
    #define TYPELIST_4(T1, T2, T3, T4) TypeList<T1, TYPELIST_3(T2, T3, T4) > 
    #define TYPELIST_5(T1, T2, T3, T4, T5) TypeList<T1, TYPELIST_4(T2, T3, T4, T5) > 
    #define TYPELIST_6(T1, T2, T3, T4, T5, T6) TypeList<T1, TYPELIST_5(T2, T3, T4, T5, T6) > 
    #define TYPELIST_7(T1, T2, T3, T4, T5, T6, T7) TypeList<T1, TYPELIST_6(T2, T3, T4, T5, T6, T7) > 
    #define TYPELIST_8(T1, T2, T3, T4, T5, T6, T7, T8) TypeList<T1, TYPELIST_7(T2, T3, T4, T5, T6, T7, T8) > 
    #define TYPELIST_9(T1, T2, T3, T4, T5, T6, T7, T8, T9) TypeList<T1, TYPELIST_8(T2, T3, T4, T5, T6, T7, T8, T9) >
    
    namespace vlad
    {
        namespace modern
        {
    
            template <class TL> struct MaxSize ;
            template <>
            struct MaxSize<NullType>
            {
                enum { value = 0 } ;
            } ;
    
            template <class Head, class Tail>
            struct MaxSize< TypeList<Head, Tail> >
            {
            private :
                enum { tailValue = size_t(MaxSize<Tail>::value) } ;
            public:
                enum { value = sizeof(Head) > tailValue ? sizeof(Head) : tailValue } ;
            } ;
    
            //TL Length
            template <class TL> struct Length ;
            template <>
            struct Length<NullType>
            {
                 enum { value = 0 } ;
            } ;
            template <class Head, class Tail>
            struct Length< TypeList<Head,Tail> >
            {
                enum { value = 1 + Length<Tail>::value } ;
            } ;
    
            //TL IndexOf
            template <typename TL, typename T > struct IndexOf ;
            template <class T>
            struct IndexOf<NullType, T>
            {
                //if not found IndexOf == max_num_of_t
                enum { value = -1 };
            };
    
            template <class Tail, class T>
            struct IndexOf<TypeList<T,Tail>,T>
            {
                    enum { value = 0 };
            };
    
            template <class Head, class Tail, class T>
            struct IndexOf<TypeList<Head,Tail>,T>
            {
              private:
                    enum { nextVal = IndexOf<Tail,T>::value };
              public:
                    enum { value = nextVal == -1 ? -1 : 1 + nextVal } ;
            };
    
            template <typename TL, unsigned int i> struct TypeAt ;
    
             template <class Head, class Tail>
             struct TypeAt<TypeList<Head, Tail>, 0>
             {
                  typedef Head type;
             };
    
             template <class Head, class Tail, unsigned int i>
             struct TypeAt<TypeList<Head, Tail>, i>
             {
                 typedef typename TypeAt<Tail, i-1>::type type;
             };
    
            template <typename  TL>
            class Variant
            {
            public :
                //compute the needed buffer size
                enum { max_size_t = MaxSize<TL>::value } ;
                enum { max_num_of_t = Length<TL>::value } ;
                //struct for alignment
                typedef struct { unsigned char buf_t[max_size_t] ; } base_t ;
    
                //default constructor
                template <typename T>
                explicit Variant() : _type_index(0)
                {
                    new (&_variant_holder) TypeAt<TL, 0>::type() ;
                }
                virtual ~Variant() { } ; //{  _type_ptr->~T() ;  }
    
                template <typename T>
                explicit Variant( const T &t )
                {
                    _type_index = IndexOf<TL, T>::value ;
                    if ( _type_index == max_num_of_t )
                        throw std::bad_cast() ;
                    new (&_variant_holder) T(t) ;
                }
    
                template <typename T>
                const T & get() { 
                    std::size_t  type_index = IndexOf<TL, T>::value ;
                    if ( type_index == max_num_of_t  || type_index != _type_index)
                        throw std::bad_cast() ;
                    T * _type_ptr = reinterpret_cast<T *>(&_variant_holder) ;
                    return *_type_ptr ; 
                }
    
            private :
                base_t _variant_holder ;
                std::size_t _type_index ;
            };
    
        } //namespace modern
    }//namespace vlad
    
    
    #endif /* _VARIANT_MODERN_HPP_ */
    

    Use case :

    typedef modern::vlad::Variant<TYPELIST_2(int, std::string)> variant_t;
    variant_t v (123) ;
    int value = v.get<int>() ;
    std::string tmp = v.get<std::string>() ; //throws exception
    
    0 讨论(0)
  • 2021-01-26 05:35

    The proper, but more advanced, approach would be actually store the values in a holder type that knows how to manage the actual type it contains.

    A simpler approach, for learning purposes, would be to map types to numbers (i.e. their position in the typelist). With that you can remember what type you are currently storing in the variant.

    To get that a working version you'll probably want to have templated constructors and setters and also an accessor function that use that type-number mapping.

    Quite simplified it could look something like this:

    template<class TypeList>
    class variant {
        unsigned type;
        void* value;
    public:
    
        // ...
    
        template<class T>
        void set_to(const T& t) {
            STATIC_ASSERT(contains<TypeList, T>::value);
            // ... clean up previous value
            type  = index_of<TypeList, T>::value;
            value = static_cast<void*>(new T(t));
        }
    
        template<class T>
        const T& get_as() {
            STATIC_ASSERT(contains<TypeList, T>::value);
            if(type == index_of<TypeList, T>::value)
                return *static_cast<T*>(value);
            else
                throw type_error();
        }
    };
    
    0 讨论(0)
提交回复
热议问题