C++ 模块是否不存在 ODR 违规?
Do C++ modules make ODR violations absent?
来自 N4720 C++ 模块草案,[basic.def.odr]/6 说:
[…] For an entity with an exported declaration, there shall be only one definition of that entity; a diagnostic is required only if the abstract semantics graph of the module contains a definition of the entity. [Note: If the definition is not in the interface unit, then at most one module unit can have and make use of the definition. — end note] […]
根据我的理解,这实际上使模板有机会只被编译器解析一次,这与当前的情况形成对比(每个翻译单元都有其定义的精确副本)。这对于具有类似大小写的其他实体也有效,例如内联 functions/variables.
我的问题源于这样一个事实,即每个翻译单元最多只能有一个实体定义(如 [basic.def.odr]/1 中所述),因此跨实体具有不同定义是未定义的行为恩。而且,由于导出的实体在整个编译单元中只有一个定义(使未导出的实体在其实现单元中是唯一的),从我的角度来看,即使不是不可能,也很难弄错定义。
最后,简单地说:模块的使用是否会(或确实或应该)使违反 ODR 规则变得不可能,或者更难出错?
如果一个项目完全模块化(即从不使用#include
),那么大多数意外的 ODR 违规行为都会消失。大多数意外的 ODR 违规是由于 #include
的性质而发生的:包括具有定义的全局变量等等。或两阶段模板查找问题,其中两个文件包含相同的模板,但由于每个文件在该模板之前包含的内容,因此两个模板的定义不同。
但是,这并不能防止更少的 "accidental" ODR 违规。因为 "same entity" 是由它的名称定义的,而实体的名称与它从中导出的模块无关,所以两个模块可以提供同一实体的不同定义。所以基本上,名称冲突。
如果单个翻译单元同时导入这两个模块,这只会成为编译错误(即:需要诊断)。如果两个单独的翻译单元每个都包含具有不同定义的模块之一,那么整个程序仍然违反 ODR,但不必对其进行诊断。
所以即使在完全模块化的代码库中,ODR 仍然可能被违反。
来自 N4720 C++ 模块草案,[basic.def.odr]/6 说:
[…] For an entity with an exported declaration, there shall be only one definition of that entity; a diagnostic is required only if the abstract semantics graph of the module contains a definition of the entity. [Note: If the definition is not in the interface unit, then at most one module unit can have and make use of the definition. — end note] […]
根据我的理解,这实际上使模板有机会只被编译器解析一次,这与当前的情况形成对比(每个翻译单元都有其定义的精确副本)。这对于具有类似大小写的其他实体也有效,例如内联 functions/variables.
我的问题源于这样一个事实,即每个翻译单元最多只能有一个实体定义(如 [basic.def.odr]/1 中所述),因此跨实体具有不同定义是未定义的行为恩。而且,由于导出的实体在整个编译单元中只有一个定义(使未导出的实体在其实现单元中是唯一的),从我的角度来看,即使不是不可能,也很难弄错定义。
最后,简单地说:模块的使用是否会(或确实或应该)使违反 ODR 规则变得不可能,或者更难出错?
如果一个项目完全模块化(即从不使用#include
),那么大多数意外的 ODR 违规行为都会消失。大多数意外的 ODR 违规是由于 #include
的性质而发生的:包括具有定义的全局变量等等。或两阶段模板查找问题,其中两个文件包含相同的模板,但由于每个文件在该模板之前包含的内容,因此两个模板的定义不同。
但是,这并不能防止更少的 "accidental" ODR 违规。因为 "same entity" 是由它的名称定义的,而实体的名称与它从中导出的模块无关,所以两个模块可以提供同一实体的不同定义。所以基本上,名称冲突。
如果单个翻译单元同时导入这两个模块,这只会成为编译错误(即:需要诊断)。如果两个单独的翻译单元每个都包含具有不同定义的模块之一,那么整个程序仍然违反 ODR,但不必对其进行诊断。
所以即使在完全模块化的代码库中,ODR 仍然可能被违反。