由于它的强大功能,C++模板在我的日常工作中一直是一种祝福.但是人们不能忽视大量使用模板(hello元编程和Boost库)导致的(非常非常非常长的)编译时间.我已经阅读并尝试了很多可能性来手动重新组织和修改模板代码,以使其尽可能快地编译.
现在我想知道是否有任何c ++编译器试图最小化解释模板类所需的时间.我可能错了,但我觉得我知道的编译器只在他们以前的版本中添加了模板解释.
我的问题是:
c ++模板代码是如此难以解释,以至于没有太多优化?(我非常怀疑)
是否有真正优化"c ++模板"解释的c ++编译器?
是否有项目开发新一代的c ++编译器来优化这一点?
如果您参加这样的项目,您的指导方针是什么?
Johannes Sch.. 14
我希望通过使用可变参数模板/右值引用来加快编译模板化代码的速度.今天,如果我们想编写在编译时执行某些操作的模板代码,我们会滥用该语言的规则.我们创建了许多重载和模板特化,这些特殊化产生了我们想要的东西,但不是以告诉编译器我们的意图的方式.因此,在构建时,编译器的快捷方式很少.请参见可变参数模板的动机
是否有项目开发新一代的c ++编译器来优化这一点?
是的,CLang是LLVM编译器基础结构的C语言前端.CLang和LLVM都使用C++编码.在CLang的开发人员中,Douglas Gregor是几个C++ 1x语言提案的作者,如可变参数模板和概念.作为参考,参见Douglas Gregor对GCC的抨击测试
http://www.freeimagehosting.net/uploads/a2e6f1dc27.png
以下是Clang和GCC 4.2中模板实例化的一些快速性能结果.测试非常简单:测量编译时间(仅限-fsyntax),用于通过模板元程序计算第N个Fibonacci数的翻译单元.Clang似乎是按照实例化的数量线性缩放(或接近它).而且,尽管你在图表中看不到它,但Clang在开始时比GCC快2倍(
Fibonacci<100>
).
CLang还处于早期阶段,但我认为它有很好的机会成为一个优秀的C++编译器.
我希望通过使用可变参数模板/右值引用来加快编译模板化代码的速度.今天,如果我们想编写在编译时执行某些操作的模板代码,我们会滥用该语言的规则.我们创建了许多重载和模板特化,这些特殊化产生了我们想要的东西,但不是以告诉编译器我们的意图的方式.因此,在构建时,编译器的快捷方式很少.请参见可变参数模板的动机
是否有项目开发新一代的c ++编译器来优化这一点?
是的,CLang是LLVM编译器基础结构的C语言前端.CLang和LLVM都使用C++编码.在CLang的开发人员中,Douglas Gregor是几个C++ 1x语言提案的作者,如可变参数模板和概念.作为参考,参见Douglas Gregor对GCC的抨击测试
http://www.freeimagehosting.net/uploads/a2e6f1dc27.png
以下是Clang和GCC 4.2中模板实例化的一些快速性能结果.测试非常简单:测量编译时间(仅限-fsyntax),用于通过模板元程序计算第N个Fibonacci数的翻译单元.Clang似乎是按照实例化的数量线性缩放(或接近它).而且,尽管你在图表中看不到它,但Clang在开始时比GCC快2倍(
Fibonacci<100>
).
CLang还处于早期阶段,但我认为它有很好的机会成为一个优秀的C++编译器.
这真的不是你问题的答案.这更多的是侧面观察.
我也不是C++语言律师,所以我可能会偏离一些细节.
但是,粗略的想法应该是正确的.
C++编译器花了这么长时间来编译模板元程序的主要原因是因为指定了模板元程序的方式.
它们不是直接指定为编译器在编译时运行的代码.以计算类型列表长度为例.
如果您可以编写如下代码:
compile_time size_t GetLength(TypeList * pTypeList) { return DoGetLength(pTypeList, 0); } compile_time size_t DoGetLength(TypeList * pTypeList, size_t currentLength) { if (pTypeList) { return DoGetLength(pTypeList->Next, ++currentLength); } else { return currentLength; } }
这是一些如何与使用它的代码分开编译,并通过一些语法暴露给语言,然后编译器将能够非常快速地执行它.
它只是一个简单的递归函数调用.
设计允许这类事物的语言是可能的.执行此操作的大多数(如lisp)是动态类型的,但可以使用静态类型.但是,它不太可能是您在C++中实现的东西.
但是,C++中的问题是代码编写如下:
templatestruct TypeList { typedef First Head; typedef Second Tail; }; template <> struct ListSize { enum { size = 0 }; }; template struct ListSize > { enum { size = 1 + ListSize ::size }; };
为了让编译器"执行"元程序,它必须:
构造"size"枚举值的初始值的依赖关系图
为图中的每个边构造模板类型
绑定每个构造的模板类型引用的所有符号
在拓扑上排序依赖图
遍历图并评估常量
这比仅仅运行O(N)递归算法要昂贵得多.
最坏的情况是O(N*M*L),其中N等于列表的长度,M是范围嵌套的级别,L是每个范围中的符号数.
我的建议是尽量减少您使用的C++模板元编程的数量.
模板的主要问题如下:
您不能(通常)将模板类的定义与其声明分开,并将其放在.cpp文件中.
结果:Everyting在头文件中.每当你包含一个头文件时,你都会包含大量代码,这些代码在正常情况下可以很好地分成.cpp文件并单独编译.每个编译单元都包含一些标题,因此,每个编译单元都包含模板大量代码,或几乎所有项目,都是通过包含的标题.
如果这是你的问题,那么请看一下相关的问题:
模板:使用前向声明来减少编译时间?
它得到了一个非常好的答案,它解决了这个问题.
基本上,它涉及实例化您需要的模板,并将它们编译为目标文件.稍后您可以链接它,并且您不必在任何地方都包含该代码.它被分成一个编译的目标文件.注意:只有当您仅使用几个实例化的模板类型时才有意义(例如,您只需要MyType
和MyType
在您的程序中).
它使用g++
旗帜-fno-implicit-templates
.
该技术非常有用,我认为它应该被整合到C++常见问题中:[35.12]为什么我不能将模板类的定义与它的声明分开并将其放在.cpp文件中?