下面,
how do I fix this c++ typelist template compile error?
我们使用现代c ++设计中的代码构建了一个类型列表。
现在的问题是 - 如何将其置于变体类中?
答案 0 :(得分:2)
/*
* 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
答案 1 :(得分:1)
正确但更高级的方法实际上是将值存储在 holder 类型中,该类型知道如何管理它包含的实际类型。
出于学习目的,更简单的方法是将类型映射到数字(即它们在类型列表中的位置)。通过它,您可以记住您当前在变体中存储的类型。
要获得该工作版本,您可能希望使用模板化构造函数和setter以及使用该类型编号映射的访问器函数。
相当简化它看起来像这样:
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();
}
};