c++ - 如何将此 C++ 类型列表构建为变体?

标签 c++ templates variant typelist

这里,

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

我们使用现代 c++ 设计的代码构建了一个类型列表。

现在的问题是——我如何将其构建到变体类中?

最佳答案

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

用例:

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

关于c++ - 如何将此 C++ 类型列表构建为变体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2150892/

相关文章:

c++ - 在模板函数中使用 STL Sort?

c++ - 仅使用静态多态性的异构容器

ocaml - OCaml在多态变体上的功能还不够多态吗?

c++ - 在 VARIANT 和 _variant_t 之间复制

c++ - 操纵 LARGE_INTEGERS

c++ - Qt Makefile 找不到自己的目录

c++ - 为什么没有显示获胜镜头?

c++ - 处理输入流运算符中的无效输入>>

c++ - 基于模板类型的枚举值

c - 将数组存储在 Gvariant 中以用于 GSettings