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;
};
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,172评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,346评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,788评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,299评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,409评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,467评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,476评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,262评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,699评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,994评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,167评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,499评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,149评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,387评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,028评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,055评论 2 352

推荐阅读更多精彩内容

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