Már*_*ldi 5 c++ one-definition-rule c++-modules
从N4720 C++模块草案中,[basic.def.odr]/6说:
[......] 对于拥有出口申报单的实体,该实体只应有一个定义; 仅当模块的抽象语义图包含实体的定义时才需要诊断.[注意:如果定义不在接口单元中,则最多一个模块单元可以拥有并使用该定义. - 尾注] [...]
根据我的理解,实际上模板只有一次机会被编译器解析一次,与当前事态形成对比(每个翻译单元的定义都有一个精确的副本).这对于具有类似情况的其他实体也是有效的,例如内联函数/变量.
我的问题来自这样一个事实:由于每个翻译单元最多只能有一个实体定义(如[basic.def.odr]/1中所述),因此在TU中对实体进行不同的定义是未定义的行为. .并且,由于导出的实体在整个编译单元中只有一个定义(使未实现的定义对于它们的实现单元是唯一的),从我的角度来看,定义错误即使不是不可能也是更难的.
最后,简单地说:将(或确实或应该)模块的使用使得不可能违反ODR规则,或者更难以出错?
如果一个项目是完全模块化的(即从不使用#include
),那么大多数意外的 ODR 违规都会消失。大多数意外的 ODR 违规是由于以下性质而发生的#include
:包括具有定义的全局变量等。或者两阶段模板查找问题,其中两个文件包含相同的模板,但由于每个文件在该模板之前包含的内容,两个模板的定义是不同的。
但是,这并不能防止较少的“意外”ODR 违规。因为“同一个实体”是由其名称定义的,而一个实体的名称与其导出的模块无关,所以两个模块可以提供同一实体的不同定义。所以基本上,名称冲突。
如果单个翻译单元导入这两个模块,这只会成为编译错误(即:需要诊断)。如果两个独立的翻译单元每个都包含一个具有不同定义的模块,那么整个程序仍然违反 ODR,但不必对其进行诊断。
因此,即使在完全模块化的代码库中,仍然可能违反 ODR。