【问题标题】:Struggling with implementation of a type list努力实现类型列表
【发布时间】:2014-07-27 23:09:50
【问题描述】:

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

【问题讨论】:

  • 我认为您不应该拥有T1T2。一个T 就足够了。
  • @KerrekSB 这是正确的,但不能解决我原来的问题。不过,感谢您指出!我相应地编辑了代码。

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


【解决方案1】:

编译器试图为条件的 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;
};

【讨论】:

    【解决方案2】:

    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&lt;A&gt; 将完全有效,但如果我们用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;
    };
    

    在上面我们假装是一个编译器,我们用B替换了每个出现的T,这并不是那么辛苦,但它对我们的primary-template提出了一个非常重要的问题.

    当编译器用T = B 实例化some_trait&lt;T&gt; 时,我们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&lt;typename T&gt; struct back;的实例化是一个只有一个参数的type_list,我们知道我们在最后一个节点。

    【讨论】:

    • @dyp 措辞已更改。
    • 嗯,很难想出一个简洁准确的条件。我喜欢这种变化;它们必须确实是有效的类型名称(别名特化会立即解析)。顺便提一句。这是一个必要但不充分的条件,例如可访问性。
    • typename type_list&lt;T&gt;::Head 不只是T?为什么不直接写 T 作为结果?
    • @Manu343726 因为在这种情况下type_list&lt;T&gt;::Head 将产生T,但对于更高级的模板可能并非如此;更好地依赖原始定义,这样如果type_list发生变化,我们就不需要更改back的定义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-31
    • 2013-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多