使用metaprogramming的目的是为了实现更多的更能,并且使花费的开销更小,其中开销是以:代码大小、维护的开销等来衡量的。另一方面,metaprogramming的最大特点在于:某些用户自定义的计算可以在程序翻译期进行。
枚举值和静态常量:
在原来的C++编译器中,在类声明的内部,枚举值是声明“真常量”(也称为常量表达式)的唯一方法。现在C++标准化过程引入了在类内部进行静态常量初始化的概念。
静态常量只能是左值。然而枚举值却不是左值(它们并没有地址),当通过引用传递枚举值的时候,并不会使用任何静态内存,就像是以文字常量的形式传递这个完成计算值一样。
一个template metaprogram可以包含下面几部分:
- 状态变量:也就是模板参数
- 迭代构造:通过递归
- 路径选择:通过使用条件表达式或者特化
- 整型(即枚举里面的值应该为整型)算法
在组织递归实例化的时候,趋向于避免在模板实参中使用递归嵌套的实例化。
例:
template <typename T, typename U>
struct Doublify {};
template <int N>
struct Trouble
{
typedef Doublify <typename Trouble<N - 1>::LongType, typename Trouble<N - 1>::LongType> LongType;
};
template<>
struct Trouble<0>
{
typedef double LongType;
};
Trouble<10>::LongType ouch;
Trouble<10>::LongType的使用不仅引发了递归实例化,而且还基于一些非常复杂的类型实例化了Doublify。
使用metaprogram来展开循环:
例:用于展开数值计算的循环,计算点乘
//loop2.hpp
#define LOOP2_HPP
// 基本模板
template <int DIM, typename T>
class DotProduct {
public:
static T result (T* a, T* b) {
return *a * *b + DotProduct<DIM-1,T>::result(a+1,b+1);
}
};
// 作为结束条件的局部特化
template <typename T>
class DotProduct<1,T> {
public:
static T result (T* a, T* b) {
return *a * *b;
}
};
// 辅助函数
template <int DIM, typename T>
inline T dot_product (T* a, T* b)
{
return DotProduct<DIM,T>::result(a,b);
}
#endif
实现文件:
#include "loop2.hpp"
int main()
{
int a[3] = { 1, 2, 3};
int b[3] = { 5, 6, 7};
std::cout << "dot_product<3>(a,b) = " << dot_product<3>(a,b)
<< '/n';
std::cout << "dot_product<3>(a,a) = " << dot_product<3>(a,a)
<< '/n';
}