读书笔记 effective c++ Item 48 通晓模板元编制程序,effectiveitem

1. TMP是什么?

模板元编制程序(template metaprogramming
TMP)是实现基于模板的C++程序的进度,它亦可在编写翻译期实施
。你能够想一想:叁个模板元程序是用C++达成的同一时候能够在C++编译器内部运营的一个主次,它的输出——从沙盘中实例化出来的C++源码片段——会像在此以前一致被编写翻译。

读书笔记 effective c++ Item 48 明白模板元编制程序,effectiveitem

2. 使用TMP的优势

要是那未有撞击到您,是因为您从未丰富尽力去想。

 

C++不是为着模板元编制程序而设计的,可是自从TMP早在一九九零年被察觉未来,它就被注脚是十二分管用的,为了使TMP的运用更加的便于,在C++语言和典型库中进入了有个别扩张。是的,TMP是被发觉的,并非被发明。当模板被增添到C++中的时候TMP那一个特点就被引进了。对于某个人来讲有着要求做的正是关心如何以一种聪明的和意料之外的法子来接纳它。

TMP有二种强大的工夫。第一,它使得部分职业变得轻巧也便是说若无TMP,那个业务做起来很难或然不容许实现其次,因为模板元编程在C++编写翻译期实施,它们能够将一部分行事从运营时移动到编写翻译期。二个结实正是有个别原先一般在运作时可以被发掘的不当,今后在编译期就可见被察觉了。别的贰个结实正是运用TMP的C++程序在大致各类地点都更加速速:越来越小的实施体,越来越短的周转时刻,越来越少的内部存款和储蓄器必要。(然则,将专门的学问从运营时移到编写翻译期的多个后果就是编写翻译时间增加了。使用TMP的主次比未有使用TMP的次序大概损耗更加长的年华来拓展编写翻译。)

1. TMP是什么?

模板元编制程序(template metaprogramming
TMP)是贯彻基于模板的C++程序的历程,它亦可在编写翻译期实践
。你可以想一想:八个模板元程序是用C++达成的同一时候能够在C++编写翻译器内部运营的三个主次,它的输出——从沙盘中实例化出来的C++源码片段——会像以前一致被编译。

3. 什么样采纳TMP?

2. 使用TMP的优势

假诺那未尝碰撞到您,是因为您未曾丰硕尽力去想。

 

C++不是为了模板元编程而设计的,可是自从TMP早在壹玖捌玖年被察觉以往,它就被认证是充足有效的,为了使TMP的施用尤其轻松,在C++语言和标准库中参加了有的扩展。是的,TMP是被察觉的,并不是被发明。当模板被增加到C++中的时候TMP这么些性格就被引进了。对于一些人的话具备需求做的正是关怀如何以一种聪明的和奇怪的章程来行使它。

TMP有三种强大的手艺。首先,它使得一些政工变得轻松也等于说只要未有TMP,这一个事情做起来很难大概不只怕完成第二,因为模板元编制程序在C++编写翻译期施行,它们得以将有个别行事从运营时移动到编写翻译期。三个结出正是部分原来一般在运维时亦可被发觉的荒唐,今后在编写翻译期就可见被开掘了。别的一个结出正是行使TMP的C++程序在大概各种上边都特别高效:越来越小的实践体,越来越短的运营时刻,更加少的内部存款和储蓄器需要。(可是,将职业从运转时移到编写翻译期的三个结果正是编写翻译时间净增了。使用TMP的主次比一贯不使用TMP的次序或然损耗越来越长的时刻来进展编写翻译。)

3.1 再一次分析Item 47中的实例

考虑在Item
47中为STL的advance写出来的伪代码。笔者早就为伪代码部分做了粗体:

 1 template<typename IterT, typename DistT>
 2 void advance(IterT& iter, DistT d)
 3 {
 4 if (iter is a random access iterator) {
 5 
 6 iter += d;                           // use iterator arithmetic
 7 
 8 }                                        // for random access iters
 9 
10 else {                                
11 
12 
13 if (d >= 0) { while (d--) ++iter; } // use iterative calls to
14 else { while (d++) --iter; } // ++ or -- for other
15 } // iterator categories
16 }

 

咱俩得以选拔typeid替换伪代码,让程序能够试行。那就生出了一个“普通的”C++方法——也正是颇具职业都在运作时举行的主意:

 1 template<typename IterT, typename DistT>
 2 void advance(IterT& iter, DistT d)
 3 {
 4 if ( typeid(typename std::iterator_traits<IterT>::iterator_category) ==
 5 typeid(std::random_access_iterator_tag)) {
 6 
 7 iter += d;                           // use iterator arithmetic
 8 
 9 }                                        // for random access iters
10 
11 else {                               
12 
13 
14 if (d >= 0) { while (d--) ++iter; } // use iterative calls to
15 else { while (d++) --iter; } // ++ or -- for other
16 } // iterator categories
17 }

 

Item
47建议这种依照typeid的措施比使用trait效能更低,因为经过选择这种方式,(1)品种测量检验发生在运维时而不是编写翻译期(2)实践运转时类型测验的代码在运作的时候必须可知。事实上,那一个事例也展示出了为什么TMP比二个“普通的”C++程序更为快捷,因为traits情势属于TMP。记住,trait使得在类型上开始展览编写翻译期if…else运算成为大概。

自家早已在后边提到过一些事物表明其在TMP中比在“普通”C++中特别便于,Item
47中也提供了一个advance的例子。Item
47中涉及了advance的基于typeid的兑现会招致编写翻译难题,看下边包车型地铁事例:

1 std::list<int>::iterator iter;
2 ...
3 advance(iter, 10);               // move iter 10 elements forward;
4 // won’t compile with above impl.

 

设想为地方调用所产生的advance的本子,将模板参数IterT和DistT替换为iter和10的连串之后,大家取得上面包车型客车代码:

 1 void advance(std::list<int>::iterator& iter, int d)
 2 {
 3 if (typeid(std::iterator_traits<std::list<int>::iterator>::iterator_category) ==
 4 typeid(std::random_access_iterator_tag)) {
 5 
 6 iter += d;
 7 
 8 // error! won’t compile
 9 
10 
11 }
12 else {
13 if (d >= 0) { while (d--) ++iter; }
14 else { while (d++) --iter; }
15 }
16 }

 

有题指标是高亮部分,正是行使+=的语句。在那些事例中,大家在list<int>::iterator上使用+=,不过list<int>::iterator是三个双向迭代器(见Item
47),所以它不支持+=。唯有随机拜见迭代器帮忙+=。以后,大家知道了+=这一行将长久不会被试行到,因为为list<int>::iteraotr实行的typeid测量试验永世都不会为真,但是编写翻译器有职务保障全数的源码都以立见成效的,尽管不被施行到,当iter不是随机访谈迭代器“iter+=d”正是无效代码。将它同基于tratis的TMP化解方案举办相比,前者把为区别门类落成的代码分别放置了不一样的函数中,各类函数中张开的操作只针对一定的品类。

3. 怎么着使用TMP?

3.2 TMP是图灵完全的

TMP已经被证实是图灵完全的(Turing-Complete),那也就代表它足够庞大到能够总计任吴双西。使用TMP,你能够评释变量,实践循环,完结和调用函数等等。可是这一个概念同“普通”C++相对应的一对看起来特别不相同。比方,Item
47中if…else条件在TMP中是怎样通过采纳模板和模板特化来呈现的。但那是先后等第(assembly-level)的TMP。TMP库(举个例子,Boost
MPL,见Item
55)提供了越来越高等其他语法,这一个语法不会让您误认为是“普通的”C++。

3.1 再度解析Item 47中的实例

虚构在Item
47中为STL的advance写出来的伪代码。笔者早已为伪代码部分做了粗体:

 1 template<typename IterT, typename DistT>
 2 void advance(IterT& iter, DistT d)
 3 {
 4 if (iter is a random access iterator) {
 5 
 6 iter += d;                           // use iterator arithmetic
 7 
 8 }                                        // for random access iters
 9 
10 else {                                
11 
12 
13 if (d >= 0) { while (d--) ++iter; } // use iterative calls to
14 else { while (d++) --iter; } // ++ or -- for other
15 } // iterator categories
16 }

 

咱俩得以选取typeid替换伪代码,让程序能够施行。那就生出了三个“普通的”C++方法——也便是具有职业都在运维时举办的秘籍:

 1 template<typename IterT, typename DistT>
 2 void advance(IterT& iter, DistT d)
 3 {
 4 if ( typeid(typename std::iterator_traits<IterT>::iterator_category) ==
 5 typeid(std::random_access_iterator_tag)) {
 6 
 7 iter += d;                           // use iterator arithmetic
 8 
 9 }                                        // for random access iters
10 
11 else {                               
12 
13 
14 if (d >= 0) { while (d--) ++iter; } // use iterative calls to
15 else { while (d++) --iter; } // ++ or -- for other
16 } // iterator categories
17 }

 

Item
47建议这种遵照typeid的艺术比使用trait成效更低,因为经过选用这种格局,(1)品类测量试验发生在运作时实际不是编写翻译期(2)进行运营时类型测量检验的代码在运作的时候必须可知。事实上,那么些例子也体现出了干吗TMP比多个“普通的”C++程序更高效,因为traits格局属于TMP。记住,trait使得在等级次序上开始展览编写翻译期if…else运算成为只怕。

自己早就在前方提到过一些东西表明其在TMP中比在“普通”C++中更加便于,Item
47中也提供了三个advance的例子。Item
47中涉及了advance的基于typeid的达成会招致编写翻译难题,看下边包车型大巴事例:

1 std::list<int>::iterator iter;
2 ...
3 advance(iter, 10);               // move iter 10 elements forward;
4 // won’t compile with above impl.

 

想念为地点调用所发出的advance的版本,将模板参数IterT和DistT替换为iter和10的种类之后,大家获取上边包车型客车代码:

 1 void advance(std::list<int>::iterator& iter, int d)
 2 {
 3 if (typeid(std::iterator_traits<std::list<int>::iterator>::iterator_category) ==
 4 typeid(std::random_access_iterator_tag)) {
 5 
 6 iter += d;
 7 
 8 // error! won’t compile
 9 
10 
11 }
12 else {
13 if (d >= 0) { while (d--) ++iter; }
14 else { while (d++) --iter; }
15 }
16 }

 

有标题标是高亮部分,正是选取+=的口舌。在那几个例子中,大家在list<int>::iterator上应用+=,然而list<int>::iterator是一个双向迭代器(见Item
47),所以它不支持+=。独有随机拜候迭代器帮助+=。今后,大家知道了+=这一行将永世不会被试行到,因为为list<int>::iteraotr实行的typeid测验永恒都不会为真,但是编写翻译器有义务有限支撑全数的源码都以行得通的,纵然不被推行到,当iter不是随机寻访迭代器“iter+=d”正是于事无补代码。将它同基于tratis的TMP化解方案展开相比较,前者把为分化品种完结的代码分别放置了差别的函数中,每种函数中开始展览的操作只针对特定的品类。

发表评论

电子邮件地址不会被公开。 必填项已用*标注