C ++模板因其强大功能而成为我日常工作的福音。但是人们不能忽视大量使用模板(hello元编程和Boost库)导致的(非常非常非常长的)编译时间。我已经阅读并尝试了很多可能性来手动重新组织和修改模板代码,以使其尽可能快地编译。
现在我想知道是否有任何c ++编译器尝试并最小化解释模板类所需的时间。我可能错了,但我觉得我知道的编译器只在他们以前的版本中添加了模板解释。
我的问题是:
答案 0 :(得分:14)
我希望通过使用可变参数模板/右值引用来加快模板化代码的编译速度。今天,如果我们想编写在编译时执行某些操作的模板代码,我们会滥用该语言的规则。我们创建了许多重载和模板特化,这些特殊化产生了我们想要的东西,但不是以告诉编译器我们的意图的方式。因此,在构建时,编译器的快捷方式很少。见Motivation for variadic templates
是否有项目开发新一代的c ++编译器来优化它?
是的,CLang是LLVM编译器基础结构的C语言前端。 CLang和LLVM都使用C ++编码。在CLang的开发人员中,Douglas Gregor是几个C ++ 1x语言提案的作者,如可变参数模板和概念。作为参考,请参阅道格拉斯格雷戈尔对GCC的反对此测试
以下是Clang和GCC 4.2中模板实例化的一些快速性能结果。测试非常简单:测量编译时间(仅限-fsyntax),用于通过模板元程序计算第N个Fibonacci数的翻译单元。 Clang似乎是按照实例化的数量线性缩放(或接近它)。而且,尽管你在图表中看不到它,但Clang在开始时比GCC快2倍(
Fibonacci<100>
)。
CLang仍在其early days中,但我认为它很有可能成为一个优秀的C ++编译器。
答案 1 :(得分:9)
这真的不是你问题的答案。这更像是一种侧面观察。
我也不是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 ++中的问题是代码编写如下:
template <typename First, typename Second>
struct TypeList
{
typedef First Head;
typedef Second Tail;
};
template <>
struct ListSize<NullType>
{
enum { size = 0 };
};
template <typename Head, typename Tail>
struct ListSize<TypeList<Head, Tail> >
{
enum { size = 1 + ListSize<Tail>::size };
};
为了让编译器“执行”元程序,它必须:
这比仅仅运行O(N)递归算法要贵得多。
最坏的情况是O(N * M * L),其中N等于列表的长度,M是范围嵌套的级别,L是每个范围中的符号数。
我的建议是尽量减少您使用的C ++模板元编程的数量。
答案 2 :(得分:7)
模板的主要问题如下:
您不能(通常)将模板类的定义与其声明分开,并将其放在.cpp文件中。
结果: Everyt在头文件中。每当你包含一个头文件时,你都会包含大量代码,这些代码在正常情况下可以很好地分成.cpp文件并单独编译。每个编译单元都包含一些标题,因此,对于模板,每个编译单元都包含很多代码,或几乎所有项目,都是通过包含的标题。
如果那是你的问题,那么请看一下相关的问题:
它有very good answer,解决了这个问题。
基本上,它涉及实例化您需要的模板,并将它们编译成目标文件。稍后您可以链接它,并且您不必在任何地方都包含该代码。它被分成一个编译的目标文件。注意:仅当您仅使用几个实例化模板类型时才有意义(例如,您的程序中只需要MyType<int>
和MyType<double>
)。
它使用g++
标记-fno-implicit-templates
。
该技术非常有用,我认为它应该被整合到C ++常见问题中:[35.12] Why can't I separate the definition of my templates class from it's declaration and put it inside a .cpp file?
答案 3 :(得分:4)
似乎g ++ 4.5在处理模板方面取得了巨大进步。以下是两个不可避免的变化。
“当打印类模板特化的名称时,G ++现在将省略任何来自默认模板参数的模板参数。”这可以被认为是一个微妙的修改,但它会对c ++模板的开发产生巨大的影响(听说过不可读的错误信息......?不再!)
“使用模板的代码的编译时间现在应该与实例化的数量呈线性比例,而不是按字母顺序扩展。”这将严重破坏编译时参数反对使用C ++模板。
请参阅gnu site了解完整信息
实际上,我已经想知道c ++模板是否还有问题!嗯,是的,有,但现在让我们关注光明的一面!
答案 4 :(得分:2)
这不是你想要的答案,但Walter Bright是第一个本机C ++编译器的主要开发人员,也是优化的c ++编译器。毕竟,他编写了自己的编程语言D.这基本上是对C ++的改进,更好地应对模板。
我不知道它为模板使用而优化的任何c ++编译器。
答案 5 :(得分:2)
gold linker可以帮助减少链接时间约5倍,这可以减少整个编译时间。它特别有用,因为链接不能以与编译相同的方式并行化。
(不是直接回答,但希望这很有帮助)。
答案 6 :(得分:1)
试试Incredibuild。它大大减少了编译/构建时间。
该产品基本上使Visual C ++能够利用空闲周期在您组织中的多台计算机上构建。我在大型项目(500 kloc)上使用了Incredibuild,其中包含大量模板代码,并且在构建时获得了很好的加速。
答案 7 :(得分:0)
我认为模板本身并不是那么复杂。我们将看到在c ++ 0x等中引入概念的时间,但目前,模板只是(几乎)作为宏,所以真正的问题不是如果你已经为模板优化了c ++编译器。问题是模板在编译时会生成如此大量的代码,这会使编译速度变慢。