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

ⅰ亾dé卋堺 提交于 2019-12-02 19:24:11

问题


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 this and built it into a variant class?


回答1:


/*
 * 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



回答2:


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();
    }
};


来源:https://stackoverflow.com/questions/2150892/how-to-build-this-c-typelist-into-a-variant

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!