191 {
192 return a[I] * i1 + _bz_meta_vectorDot
193 (a, i2, i3, i4, i5, i6, i7, i8, i9);
194 }
195 };
196
197 template<>
198 class _bz_meta_vectorDot<0,0> {
199 public:
200 template
201 static inline _bz_meta_nullOperand f(const T_expr1&, const T_expr2&)
202 { return _bz_meta_nullOperand(); }
203
204 template
205 static inline _bz_meta_nullOperand
206 dotWithArgs(const T_expr1& a, P_numtype2 i1, P_numtype2 i2=0,
207 P_numtype2 i3=0, P_numtype2 i4=0, P_numtype2 i5=0, P_numtype2 i6=0,
208 P_numtype2 i7=0, P_numtype2 i8=0, P_numtype2 i9=0, P_numtype2 i10=0)
209 {
210 return _bz_meta_nullOperand();
211 }
212 };
这段代码远比它乍看上去的简单。_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单元):
213 template
214 struct Typelist
215 {
216 typedef T Head;
217 typedef U Tail;
218 };
显然,Typelist没有任何状态,也未定义任何操作,其作用只在于携带类型信息,它并未打算被实例化,因此,对于Typelist的任何处理都必然发生于编译期而非运行期。
Typelist可以被无限扩展,因为模板参数可以是任何类型(包括该模板的其他具现体)。例如:
219 Typelist
就是一个包含有char、int、float三种类型的Typelist。
按照Loki的约定,每一个Typelist都必须以NullType结尾。NullType的作用类似于传统C字符串的“\0”,它被声明于Loki程序库的NullType.h文件中:
220 class NullType;
NullType只有声明,没有定义,因为Loki程序库永远都不需要创建一个NullType对象。
让我们看看IndexOf模板元程序,它可以在一个Typelist中查找给定类型的位置(摘自Loki程序库的Typelist.h单元):
221 template
222 struct IndexOf;
223
224 template
225 struct IndexOf
226 {
227 enum { value = -1 };
228 };
229
230 template
231 struct IndexOf
232 {
233 enum { value = 0 };
234 };
235
236 template
237 struct IndexOf
238 {
239 private:
240 enum { temp = IndexOf
241 public:
242 enum { value = (temp == -1 -1 : 1 + temp) };
243 };
IndexOf 提供了一个原始模板和三个局部特化版。算法非常简单:如果TList(就是一个Typelist)是一个NullType,则value为-1。如果 TList的头部就是T,则value为0。否则将IndexOf施行于TList的尾部和T,并将评估结果置于一个临时变量temp中。如果temp为 -1,则value为-1,否则value为1 + temp。
为了加深你对Typelist采用的模板元编程技术的认识,我从Loki程序库剥离出如下代码,放入一个typelistlite.h文件中:
244 // typelistlite.h
245
246 // 声明Nulltype
247 class NullType;
248
249 // Typelist的定义
250 template
251 struct Typelist
252 {
253 typedef T Head;
254 typedef U Tail;
255 };
256
257 // IndexOf的定义
258
259 // IndexOf原始模板
260 template
261
262 // 针对NullType的局部特化版
263 template
264 struct IndexOf
265 {
266 enum { value = -1 };
267 };
268
269 // 针对“TList头部就是我们要查找的T”的局部特化版
270 template
271 struct IndexOf
272 {
273 enum { value = 0 };
274 };
275
276 // 处理TList尾部的局部特化版
277 template
278 struct IndexOf
279 {
280 private:
281 enum { temp = IndexOf
282 public:
283 enum { value = (temp == -1 -1 : 1 + temp) };
284 };
测试程序如下:
285 // typelistlite_test.cpp
286
287 #include
288 #include "typelistlite.h"
289
290 // 自定义类型Royal
291 class Royal {};
292
293 // 定义一个包含有char、int、Royal和float的Typelist
294 typedef Typelist
295
296 int main()
297 {
298