template<>
class _bz_meta_vectorDot<0,0> {
public:
template<class T_expr1, class T_expr2>
static inline _bz_meta_nullOperand f(const T_expr1&, const T_expr2&)
{ return _bz_meta_nullOperand(); }
template<class T_expr1, class P_numtype2>
static inline _bz_meta_nullOperand
dotWithArgs(const T_expr1& a, P_numtype2 i1, P_numtype2 i2=0,
P_numtype2 i3=0, P_numtype2 i4=0, P_numtype2 i5=0, P_numtype2 i6=0,
P_numtype2 i7=0, P_numtype2 i8=0, P_numtype2 i9=0, P_numtype2 i10=0)
{
return _bz_meta_nullOperand();
}
};
这段代码远比它乍看上去的简单。_bz_meta_vectorDot类模板使用了一个临时变量loopFlag来存放每一步循环条件的评估结果,并使用了一个完全特化版作为递归终结的条件。需要说明的是,和几乎所有元程序一样,这个临时变量作用发挥于编译期,并将从运行代码中优化掉。
Todd是在Blitz++数值数组库的主要作者。这个程序库(以及MTL和POOMA等程序库)例证了模板元程序可以为我们带来更加高效的数值计算性能。Todd宣称Blitz++的性能可以和对应的Fortran程序库媲美。
Loki程序库:活用模板元编程技术的典范
模板元编程的价值仅仅在于高性能数值计算吗?不仅如此。Loki程序库以对泛型模式的开创性工作闻名于C++社群。它很巧妙地利用了模板元编程技术实现了Typelist组件。Typelist是实现Abstract Factory、Visitor等泛型模式不可或缺的基础设施。
就像C++标准库组件std::list提供对一组数值的操作一样,Typelist可以用来操纵一组类型,其定义非常简单(摘自Loki程序库Typelist.h单元):
template <class T, class U>
struct Typelist
{
typedef T Head;
typedef U Tail;
};
显然,Typelist没有任何状态,也未定义任何操作,其作用只在于携带类型信息,它并未打算被实例化,因此,对于Typelist的任何处理都必然发生于编译期而非运行期。
Typelist可以被无限扩展,因为模板参数可以是任何类型(包括该模板的其他具现体)。例如:
Typelist<char, Typelist<int, Typelist<float, NullType> > >
就是一个包含有char、int、float三种类型的Typelist。
按照Loki的约定,每一个Typelist都必须以NullType结尾。NullType的作用类似于传统C字符串的“\0”,它被声明于Loki程序库的NullType.h文件中:
class NullType;
NullType只有声明,没有定义,因为Loki程序库永远都不需要创建一个NullType对象。
让我们看看IndexOf模板元程序,它可以在一个Typelist中查找给定类型的位置(摘自Loki程序库的Typelist.h单元):
template <class TList, class T>
struct IndexOf;
template <class T>
struct IndexOf<NullType, T>
{
enum { value = -1 };
};
template <class T, class Tail>
struct IndexOf<Typelist<T, Tail>, T>
{
enum { value = 0 };
};
template <class Head, class Tail, class T>
struct IndexOf<Typelist<Head, Tail>, T>
{
private:
enum { temp = IndexOf<Tail, T>::value };
public:
enum { value = (temp == -1 ? -1 : 1 + temp) };
};
IndexOf提供了一个原始模板和三个局部特化版。算法非常简单:如果TList(就是一个Typelist)是一个NullType,则value为-1。如果TList的头部