Fork me on GitHub

初识c++模板元编程

模板元编程(Template metaprogramming,简称TMP)是编译器内执行的程序,编译器读入template,编译输出的结果再与其他源码一起经过普通编译过程生成目标文件。通俗来说,普通运行程序是编译器生成的机器码,由处理器解释执行得到结果,TMP则是编译器实例化template过程中得到结果。TMP已被证明是图灵完备的机器,不过模板实例化通常需要消耗巨大的编译器资源,而且难以追踪错误,没有合适的调试器,所以在实际开发中很少使用。

TMP有两个重要的作用:

  1. 将工作从运行期转移到编译期,一些在运行期才能发现的错误在编译时就找出来了。
  2. 产生较小的可执行文件,较短的运行时间,较少的内存需求。当然代价就是增加了编译时间。

下面让我们来看一个利用TMP计算3的幂的例子

template<int N>
class Pow3 {
 public:
  enum {result=3*Pow3<N-1>::result};
};

template<>
class Pow3<0> {
 public:
  enum {result=1};
};

int main() {
  std::cout<<"Pow3<7> = "<<Pow3<7>::result<<std::endl; 
}

 

Pow<7>的实例化导致Pow3<6>的实例化,Pow3<6>又出发Pow3<5>的实例化,递归直至Pow3<0>结束,Pow<7>::result直接被常量值替换。

一个TMP程序可以包含以下几部分:

  • 状态变量:即模板参数
  • 迭代构造:TMP没有循环等构件,全部用递归实现,另一方面递归的实例化也是降低编译器效率的主要原因。
  • 路径选择:通过使用条件表达式或者特化。
  • 整形算法(即枚举)

c++中,在类内部声明常量值只有枚举和静态常量初始化两种方式。上面的例子中可以将枚举改成静态常量,

template<int N>
class Pow3 {
 public:
  static int const result=3*Pow3<N-1>::result;
};

template<>
class Pow3<0> {
 public:
  static int const result=1;
};

 

不过静态常量是左值,如果将结果作为引用参数传递给一个函数,

void foo(int const&);

foo(Pow3<7>::result);

编译器必须获取 Pow3<7>::result的地址,这会强制编译器实例化静态成员的定义,并分配内存,这就跳出了编译期范围。

而枚举不是左值,没有这个约束,通过引用传递的时候跟使用常量值形式是一样的,所以一般都用枚举类型。

 

Reference:

《c++ templates: the complete guide》

《effective c++》

posted on 2014-04-23 00:26  coderkian  阅读(512)  评论(0编辑  收藏  举报


作者:coderkian
出处:http://www.cnblogs.com/coderkian/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。