Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;链接模板实例_C++_Templates_Hyperlink - Fatal编程技术网

C++ C++;链接模板实例

C++ C++;链接模板实例,c++,templates,hyperlink,C++,Templates,Hyperlink,如果我在头文件中定义一个由两个不同翻译单元包含的函数(可能是类成员函数,但不是内联的),我会得到一个链接错误,因为该函数是多重定义的。模板则不是这样,因为在编译器解析模板化类型的对象声明之前,模板是不可编译的类型。这使我意识到,我不知道编译模板代码的驻留和链接方式,因为C++不只是创建多个代码副本来定义SomeTemplateClass。任何信息将不胜感激。 谢谢 它实际上创建了多个副本。这些副本是特殊的,不违反“一个定义”规则。一些链接器将出现,删除副本,并重新链接使用它们的函数;并非所有人都

如果我在头文件中定义一个由两个不同翻译单元包含的函数(可能是类成员函数,但不是内联的),我会得到一个链接错误,因为该函数是多重定义的。模板则不是这样,因为在编译器解析模板化类型的对象声明之前,模板是不可编译的类型。这使我意识到,我不知道编译模板代码的驻留和链接方式,因为C++不只是创建多个代码副本来定义SomeTemplateClass。任何信息将不胜感激。
谢谢

它实际上创建了多个副本。这些副本是特殊的,不违反“一个定义”规则。一些链接器将出现,删除副本,并重新链接使用它们的函数;并非所有人都这样做。

这是特定于实现的

一些编译器会为它们实例化的每个翻译单元反复生成相同的模板实例,并让链接器折叠副本。
当链接器还不能胜任这项任务时,模板因“代码膨胀”而名声不佳。如今,这可能是不应该的。有些实现甚至会在编译到相同的目标机器代码时折叠不同的实例化。(如
f()
f()
,因为指针类型只是生成的机器代码中的地址。)

其他人会将模板编译推迟到链接时间,可能还有其他方法来处理这个问题。正如我所说,这取决于实施

这些都有不同的优点和缺点。由于缺乏真正的模块概念,我怀疑是否有人会想出完美的方案


使用
export
时,编译器需要预编译模板代码并根据请求实例化。然而,除了一家供应商之外,没有人为他们的编译器实现了
export
,现在它被删除了
  • 贪婪实例化,编译器在使用它的每个编译单元中生成一个实例化,然后链接器丢弃除一个以外的所有实例化(这不仅仅是代码大小优化,它是必需的,以便函数地址、
    静态变量等是唯一的)。这是最常见的模型

  • 查询实例化,其中编译器有一个已完成实例化的数据库。当需要实例化时,将检查并更新数据库。我知道的唯一一个使用它的编译器是Sun的,默认情况下不再使用它了

  • 迭代实例化,其中实例化由链接器进行(直接或通过将它们分配给编译单元,然后重新编译)。这是CFront使用的模型——也就是说,历史上它是第一个使用的模型——也被使用EDG前端的编译器使用(与CFront相比有一些优化)


(见C++模板,David Vandevoorde和Nicolai Josuttis的完整指南。另一个在线参考是,更关心编译模型,但仍然有实例化机制的描述)。

< P>所有模板函数都隐式内联。正如类声明中定义的方法是隐式内联的一样

当我说隐式内联时,我指的是这个词更现代的用法。请参阅我的详细描述

简而言之,
inline
static
extern
都是同级链接指令。inline告诉链接器忽略函数的重复定义。通常这意味着链接器将选择一个定义并将其用于所有编译单元。我不知道有哪个编译器会在最终的可执行文件中留下所有重复的模板代码

模板实例化存储在哪里?

它们以与内联函数相同的方式存储在相同的位置。具体细节取决于编译器。

这取决于编译器(因为标准中没有规定),并且使用了几种技术。这对Alexandre来说是相当糟糕的,因为很少有书会讨论这一点,而且你没有提到你期望答案在哪里。OP实际上是在问一个关于“一个定义”规则的好问题。并非所有编译器都是这样。IIRC,Comeau将实例化延迟到链接时间。我认为cfront也做到了这一点。所有这些都必须做到,否则指向同一函数模板生成的函数的指针将无法按照标准要求进行比较。@Maxim如果有点含糊,您的注释是正确的。All must do=>所有链接器都必须删除重复的副本。@Maxim-这并不像您预期的那么清楚。内联函数也有此要求,正如您所期望的,不需要链接器来删除所有副本。实际上,所有需要的是,如果地址和所取的地址相同,@疯狂埃迪:C++标准只规定了最小的要求,正如你正确指出的,相同函数的地址只有当和取的时候必须相等。进入现实。因为动态链接目前不在C++的范围内(因为多线程是),所以支持共享库的真实世界工具链必须以某种方式解决这个问题,因为还不知道函数是否在共享库中被占用,也可能只在运行时加载。gcc工具链通过利用所谓的模糊链接来解决这个问题。啊,这似乎是正确的答案,包括阅读更多关于它的参考资料。很好的回答,
+1
来自我!关于出口的旁注。它没有被弃用,而是被删除了!comeau小组要求删除该功能,而不仅仅是弃用。因为他们有唯一实现导出的编译器,所以委员会同意了。是的,你说得对,它被删除了。这是由EDG(Comeau的基础)提出的,他强烈反对将其纳入标准