C++模板元编程中的类型推理

谈C++模板元编程必然要谈的是类型推理。因为C++的内置类型非常简单(这里不考虑STL),并不需要用到复杂的类型推理机制也能良好的使用,但是在具体项目开发中往往需要对自定义类型添加类型推理,这里就对这个问题进行探讨。


  • 直接类型推理
    直接类型推理,就是给定模板类型参数,返回类型参数,我们用模板类来实现。类型推理可以看成定义在类型空间上的运算,包括一元运算,二元运算或者更多参数类型。利用模板类和typedef以及辅助的宏定义可以实现直接类型推理。下面是一个单参数类型推理:
struct Nulltype {};
template<typename T>
struct TypeInferenceT
{
  typedef Nulltype type; // default
};
#define __DEFINE_TYPE_INFER__(T, T1) 、
template<> \
struct TypeInferenceT<T> \
{ \
  typedef T1 type; \
};
// ...
__DEFINE_TYPE_INFER__(int, float)
__DEFINE_TYPE_INFER__(float,double)
// ...

下面是二元参数类型推理,相对来说更常用,比较适合二元函数的类型推理,我们这里直接用一个二元函数(类中的静态函数)来举例:

template<typename T>
struct TypeIdT
{
  static const int value = -1;
};
template<int N>
struct TypeT
{
  typedef Nulltype type;
};

#define __DEFINE_TYPEID__(T, ID) \
template<> struct TypeIdT<T> { static const int value = ID; }; \
template<> struct TypeT<ID>{ typedef T type; };

template<typename T1, typename T2>
struct Op2
{
  static const id1 = TypeIdT<T1>::value;
  static const id2 = TypeIdT<T2>::value;
  static const id = (id1>id2)?id1:id2
  typedef typename TypeT<id>::type type;
  static type func(T1 v1, T2 v2) { /* ... Implementation ... */ }
}; 

上述代码的意义如下:

  1. 利用两个模板类和一个宏,将一个整数id和类型一一对应起来
  2. 在模板类Op2<T1,T2>中利用编译期常量作为推导依据,获得两个类型中id值较大的那个类型,作为静态成员函数func(T1,T2)的返回值类型
  • 部分模板匹配的直接类型推理
    利用部分模板匹配技术,实现对一批类型的匹配。例如:
template<typename T>
struct MyTemplateClass1T { /* ... */ };

template<typename T>
struct TypeIdT<MyTemplateClass1T<T> >
{
  static const int value = TypeIdT<T>::value + 1024;
};

上述类型推理的效果是对于所有的类型T,都有MyTemplateClass1T<T>的类型ID号都可以从T的类型ID号增加1024计算得到。
这个技术对自定义模板类非常有效,如自定义复数类型、向量类型、矩阵类型等等。

  • 更复杂的类型推理:高阶类型推理

高阶类型其实是指参数类型(或像前面说的类型函数),对C++型而言就是类模板,例如前面的MyTemplateClass1T就是个带一个类型参数的高阶类型
高阶类型也能参与类型推理(并不是指部分模板参数匹配技术)
例如我们需要将两个参数模板类型符合起来:

template<template<typename>class U>
struct FunctorT
{
  template<typename T1, typename T2>
  struct impl
  {
    typedef T2(*func_t)(T1);
    static U<T2> fmap(func_t func, const U<T1>& ut1)
    {
      U<T2> ut2;
      ut2.resize(ut1.size());
      for(size_t i=0; i<ut2.size(); ++i)
      {
        ut2[i] = func(ut1[i]);
      }
      return ut2;
    }
  };
};

上述模板类型利用高阶类型(U<T>)作为输入参数,得到一个泛化的模板类(FunctorT<U>::impl<T1,T2>),该类型可以用来实现函数式中的fmap(默认实现仅对包含.size和.operator[]接口的类型U有效)。

  • 其他推理
    其他C++类型推理技术主要就是利用前面两种推理机制通过组合构造来产生更复杂的类型推理机制,其中有一些模板元编程常用的辅助类型推理工具,如:
template<bool cond = false, typename T1, typename T2>
struct meta_if { typedef T2 type; }
template<typename T1, typename T2>
struct meta_if<true,T1,T2> { typedef T1 type; };
template<typename T1, typename T2>
struct Cons
{
  typedef T1 type1;
  typedef T2 type2;
};
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • C++ 模板简介 一、模板 使用模板的目的就是能够让程序员编写与类型无关的代码。 模板是一种对类型进行参数化的工具...
    MinoyJet阅读 2,428评论 0 12
  • 夜与节能灯 仰面捧着全球史 用合法的姿势 合情合理的进去了梦乡 梦乡发生在孔雀王国 我陡然成了婆罗门 摇着蒲扇布道...
    竹帛攻玉阅读 160评论 1 1
  • 免费公交 文•萧山 老张在县城中学教历史,去年七月份刚办了退休手续,一心在家管孙子。 退休后的老张一下子很难适应这...
    仲李健萧山书屋阅读 306评论 0 1
  • 11点 北京 我向你道了晚安,拉上深蓝色的床帘,打开暖黄色的小灯,此刻,窗外风声不大,我在想你。 和你相遇很巧合,...
    青木_3f96阅读 265评论 0 0
  • 因为我之前两家公司都是有测试的,所以跟你们讲讲测试的具体工作 技能点:1.SQL 你必须会操作;2.网络抓包你需要...
    Spectator_Jin阅读 225评论 0 0