族谱网 头条 人物百科

模板元编程

2020-10-16
出处:族谱网
作者:阿族小谱
浏览:390
转发:0
评论:0
模板元编程的构成要素使用模板作为元编程的技术需要两阶段的操作。首先,模板必须被定义;第二,定义的模板必须被实体化才行。模板的定义描述了生成源码的一般形式,而使实体化则导致了某些源码的组合根据该模板而生成。模板元编程是一般性地图灵完全(Turing-complete),这意味着任何可被电算软件表示的运算都可以通过模板元编程以某种形式去运算。模板与宏(macros)是不同的。所谓宏只不过是以文字的操作及替换来生成代码,虽然同为编译期的语言特色,但宏系统通常其编译期处理流的能力(compile-timeprocessflowabilities)有限,且对其所依附之语言的语义及类型系统缺乏认知(一个例外是LISP的宏)。模板元编程没有可变的变量——也就是说,变量一旦初始化后就不能够改动。因此他可以被视为函数式编程(functionalprogramming)的一种形式。使用模板元编程模板元编程的语...

模板元编程的构成要素

使用模板作为元编程的技术需要两阶段的操作。首先,模板必须被定义;第二,定义的模板必须被实体化才行。 模板的定义描述了生成源码的一般形式,而使实体化则导致了某些源码的组合根据该模板而生成。

模板元编程是一般性地图灵完全(Turing-complete),这意味着任何可被电算软件表示的运算都可以通过模板元编程以某种形式去运算。

模板与宏(macros)是不同的。所谓宏只不过是以文字的操作及替换来生成代码,虽然同为编译期的语言特色,但宏系统通常其编译期处理流的能力(compile-time process flow abilities)有限,且对其所依附之语言的语义及类型系统缺乏认知(一个例外是LISP的宏)。

模板元编程没有可变的变量——也就是说,变量一旦初始化后就不能够改动。因此他可以被视为函数式编程(functional programming)的一种形式。

使用模板元编程

模板元编程的语法通常与一般的程序语法迥异,他有其实际的用途。一些使用模板元编程的共同理由是为了实现泛型编程(generic programming)或是展现自动编译期最优化,像是只要在编译期做某些事一次就好,而无需每次程序运行时去做。

编译期类别生成

以下将展示究竟何谓"编译期程序设计"。阶乘是一个不错的例子,在此之前我们先来回顾一下一般C++中阶乘函数的递归写法:

intfactorial(intn){if(n==0)return1;returnn*factorial(n-1);}voidfoo(){intx=factorial(4);// == (4 * 3 * 2 * 1 * 1) == 24inty=factorial(0);// == 0! == 1}

以上的代码会在程序运行时决定4和0的阶乘。

现在让我们看看使用了模板元编程的写法,模板特化提供了"递归"的结束条件。这些阶乘可以在编译期完成计算。以下源码:

templatestructFactorial{enum{value=N*Factorial::value};};templatestructFactorial{enum{value=1};};// Factorial::value == 24// Factorial::value == 1voidfoo(){intx=Factorial::value;// == 24inty=Factorial::value;// == 1}

代码如上在编译时期计算4和0的阶乘值,使用该结果值仿佛他们是预定的常数一般。

虽然从程序功能的观点来看,这两个版本很类似,但前者是在运行期计算阶乘,而后者却是在编译期完成计算。 然而,为了能够以此方式使用模板,编译器必须在编译期知道模板的参数值,也就是Factorial::value只有当X在编译期已知的情况下才能使用。换言之,X必须是常数(constant literal)或是常数表示式(constant expression),像是使用sizeof运算符。

编译期代码最优化

以上阶乘的示例便是编译期代码最优化的一例,该程序中使用到的阶乘在编译期时便被预先计算并作为数值常数植入运行码当中,节省了运行期的经常开销(计算时间)以及存储器足迹(memory footprint)。

编译期循环展开(loop-unrolling)是一个更显著的例子,模板元编程可以被用来产生n维(n-dimensional)的向量类别(当然n必须在编译期已知)。与传统n维向量比较,他的好处是循环可以被展开,这可以使性能大幅度提升。考虑以下例子,n维向量的加法可以被写成:

templateVector&Vector::operator+=(constVector&rhs){for(inti=0;i<dimension;++i)value[i]+=rhs.value[i];return*this;}

当编译器实体化以上的模板函数,可能会生成如下的代码:

templateVector&Vector::operator+=(constVector&rhs){value[0]+=rhs.value[0];value[1]+=rhs.value[1];return*this;}

因为模板参数dimension在编译期是常数,所以编译器应能展开for循环。

静态多态

多态是一项共通的标准编程工具,派生类的对象可以被当作基类的对象之实体使用,但能够调用派生对象的函数,或称方法(methods),例如以下的代码:

classBase{public:virtualvoidmethod(){std::cout<<"Base";}};classDerived:publicBase{public:virtualvoidmethod(){std::cout<method();//outputs "Derived"deletepBase;return0;}

唤起的 virtual 函数是属于位于继承最下位之类别的。这种动态多态(dynamically polymorphic)行为是借由拥有虚函数的类别所产生的虚函数表(virtual look-up tables)来实行的。虚函数表会在运行期被查找,以决定该唤起哪个函数。因此动态多态无可避免地必须承担这些运行期成本。

然而,在许多情况下我们需要的仅是可以在编译期决定,无需变动的多态行为。那么一来,奇怪的递归模板样式(Curiously Recurring Template Pattern;CRTP)便可被用来达成静态多态。如下例:

templatestructbase{voidinterface(){// ...static_cast(this)->implementation();// ...}};structderived:base{voidimplementation();};

这里基类模板有着这样的优点:成员函数的本体在被他们的宣告之前都不会被实体化,而且它可利用 static_cast 并通过自己的函数来使用派生类的成员,所以能够在编译时产生出带有多态特性的对象复合物。在现实使用上,Boost迭代器库[1]便有采用 CRTP 的技法。

其他类似的使用还有"Barton-Nackman trick(英文)",有时候被称作"有限制的模板扩张",共同的功能被可以放在一个基类当中,作为必要的构件使用,以此确保在缩减多余代码时的一致行为。

模板元编程的优缺点

编译期对运行期:因为模板的运算以及展开都是在编译期,这会花相对较长的编译时间,但能够获得更有效率的运行码。这项编译期花费一般都很小,但对于大项目或是普遍依赖模板的程序,也许会造成很大的编译开销。

泛型程序设计:模板元编程允许程序员专注在架构上并委托编译器产生任何客户码要求的实现。因此,模板元编程可达成真正的泛用代码,促使代码缩小并较好维护。

可读性:对于C++来说,模板元编程的语法及语言特性比起传统的C++编程,较难以令人理解。因此对于那些在模板元编程经验不丰富的程序员来说,程序可能会变的难以维护。(这要视各语言对于模板元编程语法的实现)

移植性:对于C++来说,由于各编译器的差异,大量依赖模板元编程(特别是最新形式的)的代码可能会有移植性的问题。

关系项目

元编程

前处理器



免责声明:以上内容版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。感谢每一位辛勤著写的作者,感谢每一位的分享。

——— 没有了 ———
编辑:阿族小谱
发表评论
写好了,提交
{{item.label}}
{{commentTotal}}条评论
{{item.userName}}
发布时间:{{item.time}}
{{item.content}}
回复
举报
点击加载更多
打赏作者
“感谢您的打赏,我会更努力的创作”
— 请选择您要打赏的金额 —
{{item.label}}
{{item.label}}
打赏成功!
“感谢您的打赏,我会更努力的创作”
返回

更多文章

更多精彩文章
打赏
私信

推荐阅读

· 模板
语法模板的声明与定义模板定义以关键字template开始,后接模板形参表(templateparameterlist),模板形参表是用尖括号括住的一个或者多个模板形参的列表,形参之间以逗号分隔。模板形参可以是表示类型的类型形参(typeparameter),也可以是表示常量表达式的非类型形参(non-typeparameter)。非类型形参跟在类型说明符之后声明。类型形参跟在关键字class或typename之后声明。模板形参可以给出默认值(defaultargumentsfortemplateparameters)。模板的非类型形参模板的非类型形参(templatenon-typeparameter)允许为下述形式:整型或枚举型到对象的指针或函数指针到对象的引用或函数引用成员指针模板的非类型参数被声明为数组或函数的,将被转换为指针或函数指针。例如:模板的非类型形参允许用const或vol...
· 极限编程
历史极限编程的创始者是肯特·贝克、沃德·坎宁安和罗恩·杰弗里斯(英语:RonJeffries),他们在为克莱斯勒综合报酬系统(英语:ChryslerComprehensiveCompensationSystem)的薪水册项目工作时提出了极限编程方法。肯特·贝克在1996年3月成为克莱斯勒系统的项目负责人,开始对项目的开发方法学进行改善。他写了一本关于这个改善后的方法学的书,并且于1999年10月将之发行,这就是《极限编程解析》(2005第二版出版)。克莱斯勒在2000年2月取消了实质上并未成功的克莱斯勒系统,但是这个方法学却一直流行在软件工程领域中。至今2006年,很多软件开发项目都一直以极限编程做为他们的指导方法学。该书阐述了如下的极限编程的哲学思想:一种社会性的变化机制一种开发模式一种改进的方法一种协调生产率和人性的尝试一种软件开发方法把极限编程一般化并用于其它类型的专案称为极限专案管...
· 编程范型
例子结构化编程对比非结构化编程命令式编程对比宣告式编程消息传递编程对比命令式编程程序编程对比函数式编程Value-levelprogramming对比Function-levelprogramming流程驱动编程对比事件驱动编程纯量编程对比阵列编程基于类编程对比基于原型编程(在面向对象编程的上下文中)Rule-basedprogramming对比Constraintprogramming(在逻辑编程的上下文中)基于组件编程(如OLE)面向方面编程(如AspectJ)符号式编程(如Mathematica)面向表格编程(如MicrosoftFoxPro)管道编程(如Unix命令中的管道)Post-objectprogramming面向主题编程自省编程或称反射编程参见ArsbasedprogrammingMemetics
· 编程语言
概论编程语言原本是被设计成专门使用在计算机上的,但它们也可以用来定义算法或者数据结构。正是因为如此,程序员才会试图使程序代码更容易阅读。编程语言往往使程序员能够比使用机器语言更准确地表达他们所想表达的目的。对那些从事计算机科学的人来说,懂得程序设计语言是十分重要的,因为在当今所有的计算都需要程序设计语言才能完成。目前发明了许多的编程语言,编程语言本身可能修改以匹配新需求,或是和其他的编程语言结合使用,尽管人们多次试图创造可以匹配所有需求的通用编程语言,但以“匹配所有需求”的标准来看,这些尝试都失败了。之所以有那么多种不同的编程语言存在的原因是,编写程序的初衷其实也各不相同;新手与老手之间技术的差距非常大,而且有许多语言对新手来说太难学;还有,不同程序之间的运行成本(runtimecost)各不相同。有许多用于特殊用途的语言,只在特殊情况下使用。例如,PHP专门用来显示网页;Perl更适合文...
· 逻辑编程
历史早在二十世纪七十年代,罗伯特·科瓦尔斯基(英语:RobertKowalski)等人提出了逻辑可以作为程序设计语言的基本思想,把逻辑和程序这两个截然不同的概念协调统一为一个概念,于是诞生了逻辑程序设计。这也是早期自动定理证明和人工智能发展的自然结果。随后,逻辑程序设计得到了迅速发展,特别是基于一阶谓词的逻辑程序设计语言,将逻辑推理对应于计算,具有丰富的表达能力、非确定性等特点,在定理机器证明、关系数据库系统、程序验证、模块化程序设计和非单调推理等都有了广泛的应用。

关于我们

关注族谱网 微信公众号,每日及时查看相关推荐,订阅互动等。

APP下载

下载族谱APP 微信公众号,每日及时查看
扫一扫添加客服微信