Effective C++ 48:了解模板元编程
Item 48: Be aware of template metaprogramming.
模板元编程(Template Metaprogramming,TMP)就是利用模板来编写那些在编译时运行的C++程序。 模板元程序(Template Metaprogram)是由C++写成的,运行在编译器中的程序。当程序运行结束后,它的输出仍然会正常地编译。
C++并不是为模板元编程设计的,但自90年代以来,模板元编程的用处逐渐地被世人所发现。
- 模板编程提供的很多便利在面向对象编程中很难实现;
- 程序的工作时间从运行期转移到编译期,可以更早发现错误,运行时更加高效。
- 在设计模式上,可以基于不同的策略,自动组合而生成具体的设计模式实现。
静态类型检查
在Item 47中提到了这样一个std::advance
的实现:
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d) {
if (typeid(typename std::iterator_traits<IterT>::iterator_category) ==
typeid(std::random_access_iterator_tag)){
iter += d;
}
...
}
list<int>::iterator it;
advance(it, 10);
其实上述代码是不能编译的,设想以下advance<list<int>::iterator, int>
中的这条语句:
iter += d;
list<int>::iterator
是双向迭代器,不支持+=
运算。虽然上述语句不会执行,但编译器不知道这一点。
编译时这条语句仍然会抛出类型错误。
模板元编程
TMP后来被证明是图灵完全的,这意味着TMP可以用来计算任何可计算的问题。你可以声明变量、执行循环、编写和调用函数等等。 但它的使用风格和普通C++完全不同。
我们来看看TMP中如何执行一个循环:
template<unsigned n>
struct Factorial{
enum{ value = n * Factorial<n-1>::value };
};
template<>
struct Factorial<0>{
enum{ value = 1 };
};
int main(){
cout<<Factorial<5>::value;
}
这是一个典型的TMP例子,其低位就像是普通编程语言中的"hello world"一样。
TMP的用途
为了更好地理解TMP的重要性,我们来看看TMP能干什么:
- 确保量纲正确。在科学计算中,量纲的结合要始终保持正确。比如一定要单位为"m"的变量和单位为"s"的变量相除才能得到一个速度变量(其单位为"m/s")。 使用TMP时,编译器可以保证这一点。因为不同的量纲在TMP中会被映射为不同的类型。
- 优化矩阵运算。比如矩阵连乘问题,TMP中有一项表达式模板(expression template)的技术,可以在编译期去除临时变量和合并循环。 可以做到更好的运行时效率。
- 自定义设计模式的实现。设计模式往往有多种实现方式,而一项叫基于策略设计(policy-based design)的TMP技术可以帮你创建独立的设计策略(design choices),而这些设计策略可以以任意方式组合。生成无数的设计模式实现方式。
本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2015/09/16/effective-cpp-48.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。