在实施类型列表时苦苦挣扎

时间:2014-06-06 15:49:32

标签: c++ templates c++11 metaprogramming template-meta-programming

出于教育目的,我想编写自己的基于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不会触发?

2 个答案:

答案 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;
};