Template metaprogramming(TMP,模板元编程)这是写template-based C++规划。编译过程。template metaprogramming随着C++写模板程序,化的过程。也就是说,TMP程序运行后,从templates详细化出来C++源代码。不再是模板了。

TMP有两个作用,一是它让某些事更easy。

比如编写STL容器,使用模板,可是存放不论什么类型元素。二是将运行在运行期的某些工作转移到了编译期。另一个结果是使用TMP的C++程序可能在其它方面更高效:较小的可运行文件、较短的运行期、较少的内存需求。可是将运行期的工作转移到了编译期。编译期可能变长了。

再看一下条款 47中的advance伪码

 template<typename Iter, typename DistT>
void advance(IteT& iter,DistT d)
{
if(iter is a random access iterator)
iter+=d;
else
{
if(d>=0)
while(d--) ++iter;
else
while(d++) --iter;
}
}

能够使用typeid让推断iter类型的伪码运行

 template<typename Iter, typename DistT>
void advance(IteT& 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;
}
}

typeid-based解法效率比traits解法低,由于在此方案中,1类型測试发生在运行期而不是编译期,2运行期类型測试代码在(或被连接于)可运行文件里。

这个样例能够说明TMP比正常的C++程序更高效,由于traits解法就是TMP。

一些东西在TMP比在正常的C++更easy。advance提供一个好样例。

advance的typeid-based实现方式可能导致编译期问题

    std::list<int>::iterator iter;
……
advance(iter,10);
void advance(std::list<int>::iterator& iter,int d)
{
if(typeid(typename std::iterator_traits<std::list<int>::iterator>::iterator_category)
==typeid(std::random_access_iterator_tag))
iter+=d;//错误
else
{
if(d>=0)
while(d--) ++iter;
else
while(d++) --iter;
}
}

在+=这个操作符上是错误调用。由于list::iterator不支持+=,它是bidirectional迭代器。

我们知道不会运行+=那一行,由于typeid那一行总是不相等;可是编译期要确保全部源代码都有效,即使是不会运行的代码。traits-based TMP解法针对不同类型运行不同代码,不会出现上述问题。

TMP已被证明是个图灵全然机器,也就是说它的威力足以计算不论什么事物。能够使用TMP声明变量、运行循环、编写调用函数……。有时候这会和正常C++相应物看起来非常是不同。比如条款 47展示的TMP if-else是由templas和其特化详细表现出来。只是那是汇编语言级的TMP。针对TMP设计的程序库(比如Boost’s MPL。**条款**55)提供更高级的语法。

为了再次认识下事物在TMP中怎样运作,来看下循环。TMP没有真正循环。循环由递归(recursion)完毕。

TMP递归甚至不是正常的递归。由于TMP递归不涉及递归函数调用,而是涉及递归模板化(recursive template instantiation)。

TMP的起手程序是在编译期计算阶乘。

TMP的阶乘运输示范怎样通过递归模板详细化实现循环,以及怎样在TMP中创建和使用变量

    template<unsigned n>
struct Factorial{
enum {value=n*Factorial<n-1>::value};
};
template<>
struct Factorial<0>{ //特殊情况。Factorial<0>的值是1
enum {value=1};
};

有了这个template metaprogram,仅仅要指涉Factorial::value就能够得到n阶乘值。循环发生在template详细化Factorial内部指涉另一个template详细化Factorial之时。

特殊情况的template特化版本号Factorial<0>是递归的结束。

每一个Factorial template详细化都是一个struct。每一个struct都声明一个名字为value的TMP变量,用来保存当前计算所获得的阶乘值。

TMP以递归模板详细化代替循环。每一个详细化有自己一份value,每一个value有其循环内适当值。

用Factorial示范TMP就像用hello world示范编程语言一样。为了领悟TMP之所以值得学习,就要先对它能够达成什么目标有一个比較好的理解。以下举三个样例:

  • 确保量度单位正确。使用TMP就能够确保在编译期全部量度单位的组合都正确。
  • 优化矩阵运算。

    条款 21以前提到过某些函数包含operator * 必须返回新对象,在条款 44中有一个SquareMatrix。

    假设这样使用

    typedef SquareMatrix<double,1000> BigMatrix;
BigMatrix m1,m2,m3,m4,m5;
……
BigMatrix result=m1 * m2 * m3 * m4 * m5;

上面乘法会产生四个暂时性矩阵,乘法还可能产生了4个作用在矩阵元素身上的循环。假设使用高级、与TMP相关的template(即expression templates),就有可能消除那些暂时对象并合并循环。所以TMP使用较少内存。运行速度也有提升。

  • 能够生成客户定制之设计模式(custom design pattern)实现品。使用policy-based design之TMP-based技术,有可能产生一些templates用来表述独立的设计项(所谓policies)。然后能够随意结合它们,导致模式实现品带着客户定制的行为。

TMP眼下还不全然成熟,语法不直观,支持的工具还不充分。

但TMP对难以或甚至不可能于运行期实现出来的行为表现能力非常吸引人。尽管TMP不会成为主流。可是会成为一些程序猿(特别是程序库的开发者)的主要粮食。

总结

  • Template metaprogramming(TMP,模板元编程)可将工作由运行期移到编译期,因而得以实现早期错误侦測和更高的运行效率。
  • TMP可被用来生成“基于政策选择组合”(based on combinations of policy choices)的客户定制代码。也可用来避免生成对某些特殊类型并不适合的代码。

版权声明:本文博主原创文章,博客,未经同意不得转载。

《Effective C++》:条款48:理解力template 元编程的更多相关文章

  1. effective c++ Item 48 了解模板元编程

    1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...

  2. 读书笔记 effective c++ Item 48 了解模板元编程

    1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...

  3. Effective C++ -----条款48:认识template元编程

    Template metaprogramming(TMP,模板元编程)可将工作由运行期移往编译期,因而得以实现早期错误侦测和更高的执行效率. TMP可被用来生成“基于政策选择组合”(based on ...

  4. 【48】认识template元编程

    1.TMP(template metaprogramming),模版元编程有两个效力:第一,它让某些事情更容易:第二,可将工作从运行期转移到编译期.

  5. 读书笔记_Effective_C++_条款四十八:了解模板元编程

    作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...

  6. C++模板元编程(C++ template metaprogramming)

    实验平台:Win7,VS2013 Community,GCC 4.8.3(在线版) 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能力,模板使 C++ 编程变得 ...

  7. 初识C++模板元编程(Template Mega Programming)

    前言:毕设时在开源库上做的程序,但是源码看得很晕(当时导师告诉我这是模板元编程,可以不用太在乎),最近自己造轮子时想学习STL的源码,但也是一样的感觉,大致了解他这么做要干什么,但是不知道里面的机制. ...

  8. 模板元编程(Template metaprogramming)

    https://en.wikipedia.org/wiki/Template_metaprogramming 没看懂...只知道了模板元编程的代码是在编译期运行的... 敲了2个例子: 1. #inc ...

  9. C++ 元编程 —— 让编译器帮你写程序

    目录 1 C++ 中的元编程 1.1 什么是元编程 1.2 元编程在 C++ 中的位置 1.3 C++ 元编程的历史 2 元编程的语言支持 2.1 C++ 中的模板类型 2.2 C++ 中的模板参数 ...

随机推荐

  1. C语言如何定义结构体

    原文地址 1. struct与typedef struct区别 struct是结构体的关键字,用来声明结构体变量如 struct  student {   char  num[10];      ch ...

  2. 让vs2010的html编辑器验证html5语法

    或者在Tools -> option -> Text Editor -> Html -> Validation

  3. Wafer管芯数量及成本估算

    芯片流片费用一般不按颗数计价,现在流片主要分为全晶圆和MPW两种方式.   MPW是现在很流行的一种tapout方法,主要是按晶圆面积来均分价格.   如果是整个wafer的话,成本主要是wafer费 ...

  4. MFC非模态对话框销毁

    非模态对话框需要重载OnCanel方法, 并调用DestroyWindow, 且不能调用基类的OnCanel重载PostNcDestroy, 需要delete掉this指针 // Overrides  ...

  5. String类的实现,内部采用字符数组实现

    #include <iostream> using namespace std; class String{ public: String(const char *str = NULL); ...

  6. 使用hibernate 分表做增删改查

    公司项目有一张表的数据量特别大.而且时间越长累积的数据量就越大. 后来DBA决定分表来解决性能问题. 分表是指   一个母体表  一群子表(结构和字段与母体表完全一样) 我们程序对母表操作其实就是对子 ...

  7. bootstrap栅格系统的div高度怎样定?

    不能直接写px,不同设置分辨不同,div宽度始终是满屏的,如果高度指定像素大小,div就不能保证长宽比例恰当了. 解决方法: height:0px;padding-bottom:100%

  8. k8s 集群基本概念

    一.概述: kubernetes是google开源的容器集群管理系统,提供应用部署.维护.扩展机制等功能,利用kubernetes能方便管理跨集群运行容器化的应用,简称:k8s(k与s之间有8个字母) ...

  9. mysql基础示例

    创建数据库.创建表等: //php中按天创建表 $sql = "create database if not exists ".$db_name; $date_time_array ...

  10. Mock.js 与 fiddler 前端模拟数据与拦截请求

    最近 工作需要  接触了Mock.js. Mock.js 是一款模拟数据生成器,旨在帮助前端攻城师独立于后端进行开发,帮助编写单元测试.提供了以下模拟功能: 根据数据模板生成模拟数据 模拟 Ajax ...