C ++模块是否缺少ODR违规行为?

时间:2018-02-07 14:07:49

标签: c++ one-definition-rule c++-modules

N4720 C ++模块草案中,[basic.def.odr] / 6说:

  

[...] 对于具有导出声明的实体,该实体只应有一个定义; 仅当模块的抽象语义图包含实体的定义时才需要诊断。 [注意:如果定义不在接口单元中,那么最多只有一个模块单元可以拥有并使用该定义。 - 结束注释] [...]

根据我的理解,实际上模板只有一次机会被编译器解析一次,与当前事态形成对比(每个翻译单元的定义都有一个精确的副本)。这对于具有类似情况的其他实体也是有效的,例如内联函数/变量。

我的问题源于这样一个事实:由于每个翻译单元最多只能有一个实体定义(如[basic.def.odr]/1中所述),因此在TU中对实体进行不同的定义是未定义的行为。并且,由于导出的实体在整个编译单元中只有一个定义(使未实现的定义对于它们的实现单元而言是唯一的),从我的角度来看,定义错误,即使不是不可能也是更难的。

最后,简单地说:将(或确实或应该)使用模块使得无法违反ODR规则,或者更难以出错?

1 个答案:

答案 0 :(得分:3)

如果项目完全模块化(即永远不会使用#include),那么大多数意外的ODR违规都会消失。大多数意外的ODR违规都是由于#include的性质而发生的:包括带有定义的全局变量等等。或两阶段模板查找问题,其中两个文件包含相同的模板,但由于每个模板之前包含的内容,两个模板的定义不同。

然而,这并没有什么可以防止意外减少"意外" ODR违规。因为"同一个实体"由其名称定义,实体名称与从中导出的模块无关,两个模块可以提供同一实体的不同定义。基本上,名称冲突。

如果单个翻译单元导入这两个模块,则这只会成为编译错误(即:需要诊断)。如果两个单独的翻译单元各自包含一个具有不同定义的模块,则整个程序仍然违反ODR,但不必对其进行诊断。

因此,即使在完全模块化的代码库中,仍然可以违反ODR。