C++模板元编程技术

一个可以运行的模板元编程例子 

    模板元编程(Template Metaprogramming)更准确的含义应该是“编‘可以编程序的’程序”,而模板元程序(Template Metaprogram)则是“‘可以编程序的’程序”。也就是说,我们给出代码的产生规则,编译器在编译期解释这些规则并生成新代码来实现我们预期的功能。 让我们来看一个可以运行的模板元编程例子 — 计算给定整数的指定次方:
// xy.h
//原始摸板
template<int Base, int Exponent>
class XY
{
public:
    enum { result_ = Base * XY<Base, Exponent-1>::result_ };
};

//用于终结递归的局部特化版
template<int Base>
class XY<Base, 0> 
{
public:
    enum { result_ = 1 };
};

    模板元编程技术之根本在于递归模板实例化。第一个模板实现了一般情况下的递归规则。当用一对整数<X, Y>来实例化模板时,模板XY<X, Y>需要计算其result_的值,将同一模板中针对<X, Y-1>实例化所得结果乘以X即可。第二个模板是一个局部特化版本,用于终结递归。 

递归模板实例化的深度和终结条件 

    可以想象,如果我们以非常大的Y值来实例化类模板XY,那肯定会占用大量的编译器资源甚至会迅速耗尽可用资源(在计算结果溢出之前),因此,在实践中我们应该有节制地使用模板元编程技术。虽然 C++标准建议的最小实例化深度只有17层,然而大多数编译器都能够处理至少几十层,有些编译器允许实例化至数百层,更有一些可达数千层,直至资源耗尽。 

利用模板元编程技术解开循环 

    模板元编程技术最早的实际应用之一是用于数值计算中的解循环。举个例子,对一个数组进行求和的常见方法是: 
// sumarray.h
template <typename T>
inline T sum_array(int Dim, T* a)
{
    T result = T();
    for (int i = 0; i < Dim; ++i) 
    { 
        result += a[i];
    }
    return result;
}
    这当然可行,但我们也可以利用模板元编程技术来解开循环: 
// sumarray2.h
// 原始模板
template <int Dim, typename T>
class Sumarray 
{
public:
    static T result(T* a)
    {
        return a[0] + Sumarray<Dim-1, T>::result(a+1);
    }
};

// 作为终结准则的局部特化版
template <typename T>
class Sumarray<1, T> 
{
public:
    static T result(T* a)
    {
        return a[0];
    }
};
用法如下: 
// sumarraytest2.cpp
#include <iostream>
#include \"sumarray2.h\"

int main()
{
    int a[6] = {1, 2, 3, 4, 5, 6};
    std::cout << \" Sumarray<6>(a) = \" << Sumarray<6, int>::result(a);
}
当我们计算Sumarray<6, int>::result(a)时,实例化过程如下: 
Sumarray<6, int>::result(a)
= a[0] + Sumvector<5, int>::result(a+1)
= a[0] + a[1] + Sumvector<4, int>::result(a+2)
= a[0] + a[1] + a[2] + Sumvector<3, int>::result(a+3)[Page]
= a[0] + a[1] + a[2] + a[3] + Sumvector<2, int>::result(a+4)
= a[0] + a[1] + a[2] + a[3] + a[4] + Sumvector<1, int>::result(a+5)
= a[0] + a[1] + a[2] + a[3] + a[4] + a[5] 
可见,循环被展开为a[0]  + a[1] + a[2] + a[3] + a[4] + a[5]。这种直截了当的展开运算几乎总是比循环来得更有效率。 也许拿一个有着600万个元素的数组来例证循环开解的优势可能更有说服力。生成这样的数组很容易,有兴趣,你不妨测试、对比一下。 

结语

    模板元编程技术并非都是优点,比方说,模板元程序编译耗时,带有模板元程序的程序生成的代码尺寸要比普通程序的大,而且通常这种程序调试起来也比常规程序困难得多。另外,对于一些程序员来说,以类模板的方式描述算法也许有点抽象。编译耗时的代价换来的是卓越的运行期性能。通常来说,一个有意义的程序的运行次数(或服役时间)总是远远超过编译次数(或编译时间)。为程序的用户带来更好的体验,或者为性能要求严格的数值计算换取更高的性能,值得程序员付出这样的代价。很难想象模板元编程技术会成为每一个普通程序员的日常工具,相反,就像Blitz++和Loki那样,模板元程序几乎总是应该被封装在一个程序库的内部。对于库的用户来说,它应该是透明的。模板元程序可以(也应该)用作常规模板代码的内核,为关键的算法实现更好的性能,或者为特别的目的实现特别的效果。 
    模板元编程技术首次正式亮相于Todd Veldhuizen的Using C++ Template Metaprograms论文之中。这篇文章首先发表于1995年5月的C++ Report期刊上,后来Stanley Lippman编辑C++ Gems一书时又收录了它。参考文献中给出了这篇文章的链接,它还描述了许多本文没有描述到的内容。 
David Vandevoorde和Nicolai M. Josuttis合著的C++ Templates: The Complete Guide一书花了一整章的篇幅介绍模板元编程技术,它同样是本文的参考资料并且也应该作为你的补充阅读材料。Andrei Alexandrescu的天才著作Modern C++ Design: Generic Programming and Design Patterns Applied的第3章Typelists对Typelist有着更为详尽的描述。 
    模板元编程技术首次正式亮相于Todd Veldhuizen的Using C++ Template Metaprograms论文之中。这篇文章首先发表于1995年5月的C++ Report期刊上,后来Stanley Lippman编辑C++ Gems一书时又收录了它。参考文献中给出了这篇文章的链接,它还描述了许多本文没有描述到的内容。 
David Vandevoorde和Nicolai M. Josuttis合著的C++ Templates: The Complete Guide一书花了一整章的篇幅介绍模板元编程技术,它同样是本文的参考资料并且也应该作为你的补充阅读材料。Andrei Alexandrescu的天才著作Modern C++ Design: Generic Programming and Design Patterns Applied的第3章Typelists对Typelist有着更为详尽的描述。 


转自:http://www.stuhack.com/biancheng/c/38685.html

你可能感兴趣的:(C++模板元编程技术)