《Effective C++》:条款48:理解力template 元编程
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 元编程的更多相关文章
- effective c++ Item 48 了解模板元编程
1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...
- 读书笔记 effective c++ Item 48 了解模板元编程
1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在 ...
- Effective C++ -----条款48:认识template元编程
Template metaprogramming(TMP,模板元编程)可将工作由运行期移往编译期,因而得以实现早期错误侦测和更高的执行效率. TMP可被用来生成“基于政策选择组合”(based on ...
- 【48】认识template元编程
1.TMP(template metaprogramming),模版元编程有两个效力:第一,它让某些事情更容易:第二,可将工作从运行期转移到编译期.
- 读书笔记_Effective_C++_条款四十八:了解模板元编程
作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...
- C++模板元编程(C++ template metaprogramming)
实验平台:Win7,VS2013 Community,GCC 4.8.3(在线版) 所谓元编程就是编写直接生成或操纵程序的程序,C++ 模板给 C++ 语言提供了元编程的能力,模板使 C++ 编程变得 ...
- 初识C++模板元编程(Template Mega Programming)
前言:毕设时在开源库上做的程序,但是源码看得很晕(当时导师告诉我这是模板元编程,可以不用太在乎),最近自己造轮子时想学习STL的源码,但也是一样的感觉,大致了解他这么做要干什么,但是不知道里面的机制. ...
- 模板元编程(Template metaprogramming)
https://en.wikipedia.org/wiki/Template_metaprogramming 没看懂...只知道了模板元编程的代码是在编译期运行的... 敲了2个例子: 1. #inc ...
- C++ 元编程 —— 让编译器帮你写程序
目录 1 C++ 中的元编程 1.1 什么是元编程 1.2 元编程在 C++ 中的位置 1.3 C++ 元编程的历史 2 元编程的语言支持 2.1 C++ 中的模板类型 2.2 C++ 中的模板参数 ...
随机推荐
- 利用指针突破C++编译器的防线
C++ 面向对象的一大特性就是封装,使用不同的访问控制符来控制外接对其的访问权限.比如: class A { public: A(): i(){} void print(){ cout << ...
- 紫薇~还记得大明湖畔的HTML5智力拼图吗?
曲线谜团是非常有趣的HTML5智力游戏,据说超过多少分会有惊喜,游戏简单易操作,偶尔抛弃那种杀死脑细胞的大型游戏,玩玩这种简单经典的益智小游戏,放松放松,也是不错的选择嘛-将游戏 通过 统一开发环境( ...
- C++编程学习52个经典网站 强力推荐
C/C++是最主要的编程语言.这里列出了50名优秀网站和网页清单,这些网站提供c/c++源代码.这份清单提供了源代码的链接以及它们的小说明.我已尽力包括最佳的C/C++源代码的网站.这不是一个完整的清 ...
- 关于ajax中async参数的感悟
async,这个参数默认为true. 就是异步去处理信息. 当把它设置为false的时候,就是同步去处理数据了. var current_lead_id = '<?php echo $curre ...
- js获取宽度设置thickbox百分比
thickbox的宽高不好设为百分比,这样遇到不同的尺寸的电脑就会出现问题. 怎么做呢? 通过js来处理. <script type="text/javascript"> ...
- linux学习 建立静态库,动态库,写简单的makefile
建立静态库 建立四个文件 bin(可运行文件),lib(库),include(头文件),src(放源文件) 这里的起的库明为add 在src文件里运行 1)gcc -c add.c //编译add.c ...
- 得到client真IP住址
1.引进的必要性log4j-1.2.14.jar package org.ydd.test; import java.util.Enumeration; import javax.servlet.ht ...
- [置顶] PHP如何扩展和如何在linux底层对php扩展?
虽然大部分php工程师都不需要知道php的C代码核心是如何运作的,有些人可能知道有个dl()函数.或者使用过一些第三方的类库,这些正是本文的重点之一. 希望对那些想把php带向更 ...
- 利用Socket实现的两个程序的通信
写的也很简单,自己觉得挺有意思了 程序如图 主要代码 public class Message { Form1 mainfrom = null; public Message() { } public ...
- Codility 1: equilibrium
提交了格灵深瞳的简历后,收到需要先进行一个简单的技术测试的通知,临时抱佛脚,先刷刷上面几道题: 题目要求 A zero-indexed array A consisting of N integers ...