也许这是蹩脚的问题,但我不明白!如果我包含<string>
或包含<vector>
多个翻译单元(不同的 .cpp),为什么它不会破坏 ODR?据我所知,每个 .cpp 的编译方式都不同,因此将为每个目标文件分别生成向量的方法代码,对吧?所以链接器应该检测到它并抱怨。即使它不会(我怀疑这是模板的特殊情况),当我将所有内容链接在一起时,它是否会在每个单元中使用一个代码或一组不同的克隆代码???
3 回答
与任何模板定义都不会破坏 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),前提是每个定义出现在不同的翻译单元中,并且只要定义满足以下要求[..]
<vector>
同一个翻译单元中的多个包含被明确允许并有效地省略,很可能通过“ #ifndef
”标题保护。
该标准对模板有一个特殊例外,允许复制否则会违反 ODR 的函数(例如具有外部链接的函数和非内联成员函数)。从 C++11 3.2/5 开始:
如果 D 是一个模板并且在多个翻译单元中定义,那么前面的要求既适用于模板定义 (14.6.3) 中使用的模板封闭范围的名称,也适用于实例化点的依赖名称(14.6.2)。如果 D 的定义满足所有这些要求,那么程序的行为就好像有一个 D 的定义。如果 D 的定义不满足这些要求,则行为未定义。
ODR 并没有说明一个结构只会在所有编译单元中声明一次——它指出如果您在多个编译单元中声明一个结构,它必须是同一个结构。vector
如果您有两个名称相同但内容不同的不同类型,则会违反 ODR 。那时,链接器会感到困惑,并且您会混淆代码和/或错误。