Effective C++——条款48(第7章)

来源:互联网 发布:海云数据 编辑:程序博客网 时间:2024/05/16 18:38

条款48: 认识 template 元编程

Be aware of template metaprogramming .

    Template metaprogramming(TMP,模板元编程)是编写 template-based C++程序并执行于编译期的过程
.所谓 template metaprogram(模板元程序)是以C++写成,执行于C++编译器内的程序.一旦TMP程序结束执行,其输出,也就是从 template 具现出来的若干C++源码,便会一如往常地被编译.
    TMP有两个伟大的效力.第一,它让某些事情更容易.第二,由于 template metaprogram执行于C++编译期,因此可将工作从运行期转移到编译期.这导致的一个结果是,某些错误原本通常在运行期才能侦测到,现在可在编译期找出来.另一个结果是,使用TMP的C++程序可能在每一方面都更高效:较小的可执行文件,较短的运行期,较少的内存需求.然而将工作从运行期转移到编译期的另一个结果是,编译时间变长了.程序如果使用TMP,其编译时间可能远长于不使用TMP的对应版本.
    考虑条款47导入的STL advance伪码:
template <typename IterT, typename DistT>void advance(IterT& iter, DistT d) {    if (iter is random access iterator) {        iter += d;      // 针对random access迭代器使用迭代器算术运算    } else {        if (d >= 0) {   // 针对其他迭代器类型反复调用++或--            while (d--)                ++iter;        } else {            while (d++)                --iter;        }    }}
    可以使用 typeid 让其中的伪码成真,取得C++对此问题的一个"正确"解决方案是所有工作都在运行期进行:
template <typename IterT, typename DistT>void advance(Iter& iter, DistT d) {    if (typeid(typename std::iterator_traits<IterT>::iterator_category)            == typeid(std::random_access_iterator_tag)) {        iter += d;    } else {        if (d >= 0) {            while (d--)                ++iter;        } else {            while (d++)                --iter;        }    }}
    条款47指出,这个 typeid-based解法的效率比traits解法低,因为在此方案中,(1)类型测试发生于运行期而非编译期,(2)"运行期类型测试"代码会出现在(或说被连接于)可执行文件中.实际上这个例子正彰显TMP如何能够比"正常的"C++程序更高效,因为traits解法就是TMP.
    traits-based TMP解法针对不同类型而进行的代码,被拆分为不同的函数,每个函数所使用的操作(操作符)都可施行于该函数所对付的类型.
    TMP的阶乘运算示范如何通过"递归模板具现化"(recursive template instantiation)实现循环,以及如何在TMP中创建和使用变量:
template <unsigned n>struct Factorial {          // 一般情况    enum { value = n * Factorial<n - 1>::value; }};template <>struct Factorial<0> {       // 特殊情况    enum { value = 1; }};
    循环发生在 template 具现体Factorial<n>内部指涉另一个 template 具现化Factorial<n - 1>时.和所有良好递归一样,需要一个特殊情况造成递归结束,这里的特殊情况是 template 特化体Factorial<0>.
    为了领悟TMP之所以值得学习,很重要的一点是先对它能够达成什么目标有一个比较好的理解.下面举出三个例子:
    1.确保量度单位正确.
    2.优化矩阵运算. 条款21曾经提出某些函数包括 operator*必须返回新对象,而条款44又导入了一个SquareMatrix class .考虑以下代码:
typedef SquareMatrix<double, 10000> BigMatrix;BigMatrix m1, m2, m3, m4, m5;       // 创建矩阵并赋予它们数值...BigMatrix result = m1 * m2 * m3 * m4 * m5;  // 计算它们的乘积
    以"正常的"函数调用动作来计算result,会创建4个暂时性矩阵,每一个用来存储对 operator*的调用结果.如果使用高级,与TMP相关的 template 技术,即所谓expression template,就有可能消除那些临时变量并合并循环,这一切都无需改变客户端的用法.于是TMP软件使用较少的内存,执行速度又有提升.
    3.可以生成客户定制的设计模式(custom design pattern)实现品. 设计模式如Strategy(详见条款55),Observer,Visitor等等都可以多种方式实现出来.运用所谓policy-based design的TMP-based技术,有可能产生一些 template 用来表述独立的设计选项,然后任意结合它们,导致模式实现品带着客户定制的行为.这项技术已被用来让若干 template 实现出智能指针的行为政策(behavioral policies),用以在编译期间生成数以百计的智能指针类型.
    注意:
    Template metaprogramming(TMP,模板元编程)可将工作由运行期移往编译期,因而得以实现早期作物侦测和更高的执行效率.
    TMP可被用来生成"基于政策选择组合"(based on combination of policy choices)的客户定制代码,也可用来避免生成对某些特殊类型并不适合的代码.


0 0
原创粉丝点击