2010-03-30 33 views
5

在使用模板函数之前,不会编译模板代码。但是,它在哪里保存了编译后的代码,它是否保存在首先使用模板函数的目标文件中?在C++中理解模板的问题

例如, main.cpp中是调用从文件test.h模板函数,编译器生成的目标文件main.o, 是对main.o文件内的模板函数?因为模板代码没有内联,是吗?

+0

是什么让你认为模板代码没有内联?尝试编译一个启用了优化的简单示例,然后反汇编结果。 – 2010-03-30 14:03:05

回答

4

它完全依赖于编译器实现。大多数编译器会生成代码,内联或类似cpp的文件,然后编译。有时候,通过优化设置,一些编译器甚至会重复使用相同的代码,而不是为每个cpp重新创建它。

所以你必须看到你的编译器的文档的更多细节。

+3

这是实际的正确答案,而不是OP所接受的答案。 – 2010-03-30 17:09:04

0

它总是内联的(意思是说,它总是内联,有内联语义)。实际上,它可能不是内联的,就像内联函数一样,但是,模板不是代码。这是一个“制作代码的模板”。因此,它通常会驻留在标题中,除特殊情况外,请参见下文。

有一个想法可以做别的,代号为“export keyword”。它被从标准中删除。

特殊情况:您可以将模板实例化编译为目标文件,而无需使用它们。这是避免内嵌所有模板代码的唯一方法。 这是它是如何做:

template class std::vector<MyClass>; 

这将迫使编译器在当前位置来实例化一个模板。的C++ 0x将有一个语法强制编译做到这一点,并有其他地方的模板实例链接搜索:

extern template class std::vector<MyClass>; // C++0x only

+4

它不是内联的,必然。它在编译单元中实例化,可以内联但不可以。 – 2010-03-30 14:00:21

+1

export关键字与内联无关,而是以编译后的形式提供模板以供客户端代码稍后实例化。 – 2010-03-30 17:11:37

0

你的意思是实例,而不是编译。在编译时,编译器会找出您的代码使用并安装(在对象文件中)所有必需版本的每个版本。

3

是的,模板功能代码在main.o文件中发出。其中一些可以内联,因为可以内联任何其他代码,但是通常,模板的代码在任何文件中发出,其中模板是实例化的。可以认为它是首先实例化模板代码以生成正常的非模板函数,然后使用编译器应用于任何其他函数的任何内联和优化来编译这些函数。

当在多个编译单元(.cpp文件)中出现相同的模板实例(例如std::vector<int>)时,会有一点困难,因为代码在每个编译单元中都被实例化。有多种处理方法,有时涉及链接阶段的清理步骤,其中重复的模板实例解析为单个实例;你的编译器手册可以提供更多关于它如何处理这种情况的信息。

+0

所以创建一个带有未使用的虚拟变量的模板类与创建类并将所有内容放在头文件中并不相同。后者将内联,模板类取决于编译器如何处理它? – hidayat 2010-03-30 14:08:11

+0

@ hidayat:不可以。同样的规则适用于“正常”类和类模板。 – 2010-03-30 14:15:34

+0

重复:我认为这是目标文件格式的标准功能,可以在链接时组合一段。我觉得* *至少有一个系统叫他们'COMDAT'部分:http://docsun.cites.uiuc.edu/sun_docs/C/solaris_9/SUNWdev/LLM/p44.html(IIRC一些连接甚至会检查节是相同的,以避免一些错误。) – BCS 2010-03-30 15:45:01

1

模板代码编译即使它从未实例化。否则,不能要求编译器发出诊断为这样:

template< typename T > 
void f() 
{ 
    blah 
} 

模板编译发生在两个阶段。除了基本检查之外,只有在实例化模板并使用实际类型填充形式参数时才能检查依赖于模板参数的所有内容。例如,这里

template< typename T > 
void f() 
{ 
    typename T::nested_type x; 
} 

T::nested_type只能在模板实例化后检查和实际类型,给出了T。但是,在编译器遇到模板定义时执行基本检查(“T::nested_type是一种类型,是否为有效的变量定义?”)。 (这就是为什么typename是必需的,顺便说一下,根据T,T::nested_type可能只是T成员的名字或静态数据成员 - 这会使得T::nested_type x;出现语法错误,所以我们必须告诉编译器将T::nested_type作为一种类型的名称)。