出于教育目的,我想编写自己的基于c++11
的类型列表。裸名单看起来像这样:
template <typename ... Ts> struct type_list;
template <typename T, typename ... Ts>
struct type_list<T, Ts ...> {
typedef T Head;
typedef type_list<Ts ...> Tail;
};
template <typename T> struct type_list<T> {
typedef T Head;
typedef null_type Tail;
};
我创建了一个名为front
的函数来提取第一个元素:
template <typename T> struct front;
template <typename TypeList>
struct front {
typedef typename TypeList::Head type;
};
哪个按预期工作,即此代码
typedef type_list<int> lst;
typedef type_list<float,int> lst2;
typedef type_list<double,float,int> lst3;
typedef type_list<char,double,float,int> lst4;
std::cout << "front(lst1): " << typeid( front<lst>::type ).name() << std::endl;
std::cout << "front(lst2): " << typeid( front<lst2>::type ).name() << std::endl;
std::cout << "front(lst3): " << typeid( front<lst3>::type ).name() << std::endl;
std::cout << "front(lst4): " << typeid( front<lst4>::type ).name() << std::endl;
产生
前面(lst1):我是 前(lst2):f
前(lst3):d
前(lst4):c
当然,back
功能是下一步,但是,我似乎无法让它发挥作用。我的代码
template <typename T> struct back;
template <typename TypeList>
struct back {
typedef typename std::conditional<std::is_same<typename TypeList::Tail, null_type>::value,
typename TypeList::Head,
typename back<typename TypeList::Tail>::type>::type type;
};
无法编译(clang 3.2
)[lst
定义为之前]:
TypeList.cc:33:71: error: no type named 'Tail' in 'null_type'
typedef typename std::conditional<std::is_same<typename TypeList::Tail, null_type>::value,
~~~~~~~~~~~~~~~~~~~^~~~
TypeList.cc:35:20: note:
in instantiation of template class 'back<null_type>' requested here
typename back<typename TypeList::Tail>::type>::type type;
^
TypeList.cc:54:44: note:
in instantiation of template class 'back<type_list<int> >' requested here
std::cout << "back(lst1): " << typeid( back<lst>::type ).name() << std::endl;
^
1 error generated.
std::conditional
不会触发?答案 0 :(得分:7)
std::conditional
std::conditonal<condition, true-type, false-type>
您的问题归结为std::conditional
中的 true - 和 false-type 必须产生有效名称,无论条件选择。
注意:如果不需要完整说明,请在本文末尾提供建议的解决方案。功能
考虑以下示例:
struct A { typedef int type; };
struct B { /* empty */ };
template<class T>
struct some_trait {
typedef typename std::conditional<
/* condition -> */ std::is_same<T, A>::value,
/* true-type -> */ typename T::type,
/* false-type -> */ void
>::type result;
};
实例化some_trait<A>
将完全有效,但如果我们使用B
实例化会发生什么?
template<>
struct some_trait<B> {
typedef typename std::conditional<
std::is_same<B, A>::value,
typename B::type, // (A), ill-formed
void
>::type result;
};
在上面我们假装是一个编译器,我们用T
取代了B
的每一次出现,这并不是那么辛苦,但它已经引起了我们的主模板
当编译器使用some_trait<T>
实例化T = B
时,std::conditional
中的 true-type 将为B::type
(A)
但是由于B
里面没有名为type
的名字,我们会得到一个编译诊断程序,说我们的代码有问题,即;我们正在尝试访问一个不存在的名称。
foo.cpp:15:37: error: no type named 'type' in 'B'
/* true-type -> */ typename T::type, // (A), ill-formed
毫无疑问,我们必须做什么,并简而言之;阻止我们的模板访问可能不存在的名称。
这样做的一种简单方法是依靠显式特化,而不是使用std::conditional
。
back
template<typename TypeList>
struct back {
typedef typename back<typename TypeList::Tail>::type type;
};
template<typename T>
struct back<type_list<T>> {
typedef typename type_list<T>::Head type;
};
注意:如果template<typename T> struct back;
的实例化只有type_list
且只有一个参数,我们就知道我们在最后一个节点。 < / p>
答案 1 :(得分:4)
错误是由于编译器尝试获取条件的else部分的类型名称,即使条件求值为true也是如此。
您可以通过创建back
。
template <typename T> struct back<type_list<T>>
{
typedef T type;
};
当然,您可以将其他实现简化为
template <typename TypeList> struct back
{
typedef typename back<typename TypeList::Tail>::type type;
};