C++ 为什么是C++';s<;向量>;模板类没有';不要违反一条定义规则?

C++ 为什么是C++';s<;向量>;模板类没有';不要违反一条定义规则?,c++,templates,language-lawyer,one-definition-rule,C++,Templates,Language Lawyer,One Definition Rule,也许这是个蹩脚的问题,但我不明白! 如果我在多个翻译单元(不同的.cpp)中包含或,为什么它不会破坏ODR? 据我所知,每个.cpp的编译方式不同,所以vector的方法代码将分别为每个对象文件生成,对吗? 所以链接器应该检测到它并进行投诉。 即使它不会(我怀疑这是模板的特例)在每个单元中使用一个代码还是不同的克隆代码集,当我将所有代码链接在一起时???同样,任何模板定义都不会破坏ODR-ODR明确指出,模板定义可能会在翻译单元之间重复,只要它们是字面上的重复(而且,因为它们是重复的,所以不可能

也许这是个蹩脚的问题,但我不明白! 如果我在多个翻译单元(不同的.cpp)中包含
,为什么它不会破坏ODR? 据我所知,每个.cpp的编译方式不同,所以vector的方法代码将分别为每个对象文件生成,对吗? 所以链接器应该检测到它并进行投诉。 即使它不会(我怀疑这是模板的特例)在每个单元中使用一个代码还是不同的克隆代码集,当我将所有代码链接在一起时???

同样,任何模板定义都不会破坏ODR-ODR明确指出,模板定义可能会在翻译单元之间重复,只要它们是字面上的重复(而且,因为它们是重复的,所以不可能有冲突或歧义)

[C++14:3.2/6]:
类类型(第9条)、枚举类型(7.2)、带外部链接的内联函数(7.1.2)、类模板(第14条)、非静态函数模板(14.5.6)、类模板的静态数据成员(14.5.1.3)、类模板的成员函数(14.5.1.1)可以有多个定义,或在程序中未指定某些模板参数(14.7、14.5.5)的模板专业化,前提是每个定义出现在不同的翻译单元中,并且定义满足以下要求[…]


同一翻译单元中的多个
被明确允许并有效地省略,更可能的是通过“
#ifndef
”头保护。

ODR没有声明一个结构在所有编译单元中只声明一次——它声明如果在多个编译单元中声明一个结构,它必须是同一个结构。如果有两个单独的
vector
类型具有相同的名称但内容不同,那么违反ODR的情况就会发生。在这一点上,链接器会变得混乱,你会混淆代码和/或错误。

该标准对模板有一个特殊的例外,允许复制可能违反ODR的函数(例如具有外部链接的函数和非内联成员函数)。从C++11 3.2/5开始:

如果D是一个模板,并且在多个翻译单元中定义, 则上述要求应同时适用于 模板定义(14.6.3)中使用的模板封闭范围, 以及实例化时的依赖名称(14.6.2)。如果 D的定义满足所有这些要求,然后程序 应表现为D的单一定义。如果 D的定义不满足这些要求,那么行为 没有定义


本质上,编译器和链接器合谋使其工作,使用内联函数使用的相同机制。不同文件中的定义应该完全正确,才能不违反ODR。巴尼:你为什么不在ODR中挑选一个你认为违反的特定短语,以及为什么声明的例外不适用?我明白了。。。但是代码复制呢??vector类包含代码(很好,模板化和足够抽象,但仍然是代码…)。所以它会为我使用它的每个翻译单元中的每个包含生成代码,对吗?所以,即使我在任何地方都使用std::vector,也应该为每个模块分别生成非常相同的代码。。。这看起来不太理想…@巴尼:是的,它是次优的。C++的编译模型(大部分继承自C)有其缺陷,而模板的添加使其更糟。这是C++编译被视为非常慢的一个主要原因,它必须解析每个编译单元的每个定义。然后它必须解决所有这些重复,并在链接时删除它们。没有人会说这是最好的方法,只是它是C++的方式。巴尼:链接器会在链接过程中删除所有重复项。事实上,编译器会在每个需要的编译单元中生成一个
向量
实现。有时这意味着内联代码(vector中的大多数方法都非常轻量级),有时则意味着独立函数。链接器将对其进行排序,并删除独立函数的任何重复副本。@barney:那么这将是一种不同的语言,不是吗?这正是当您修改标题中的定义,但不重建包括该标题在内的所有翻译单元时所发生的情况。