谨防。ODR 仅涉及将包含在结果程序中的定义。这意味着这与库中可能存在的符号无关,因为(普通)链接器不会加载整个库,而只会加载解析符号所需的部分。例如在这段代码中:
#include <cmath>
double log(double) {return 1.0;}
int main()
{
log(1.0);
}
没有违反 ODR:
- C 标准库中的日志符号仅包含在
std
命名空间中,并且根本没有冲突
- 或者它也包含在全局命名空间中
在后一种情况下,声明与来自 cmath 的声明 double log(double)
不冲突,因为它是相同的。并且由于符号log
已经定义,它从标准库中的定义将不会包含在程序中。因此,log
程序中只存在一个函数定义,即:double log(double) {return 1.0;}
.
log
如果您从数学库中提取包含的对象模块并将其显式链接到您的程序中,情况会有所不同。因为目标模块总是包含在结果程序中,而库中的目标模块只有在解析未定义的符号时才会有条件地包含。
标准参考:
C++11 的草案 n3337 或 C++14 的 n4296(或最新版本的 n4618)在第 2.2 段翻译阶段 [lex.phases] 中有明确说明:
§9。所有外部实体引用均已解析。链接库组件以满足对当前翻译中未定义的实体的外部引用。所有此类翻译器输出都被收集到程序映像中,该程序映像包含在其执行环境中执行所需的信息。
如图所示,代码仅使用一个翻译单元,并且log
已在其中定义,因此不会使用库中的定义。