首页 > 解决方案 > 由于标头中的匿名命名空间导致 ODR 违规

问题描述

通过阅读标准,我无法确定以下代码是否违反 ODR:

// a.h
#ifndef A_HEADER_FILE
#define A_HEADER_FILE

namespace {
int v;
}

inline int get_v() { return v; }

#endif // A_HEADER_FILE

// a.cpp
#include "a.h"

void f() {
  int i = get_v();
  // ...
}

// b.cpp
#include "a.h"

void g() {
  int i = get_v();
  // ...
}

(来源:https ://wiki.sei.cmu.edu/confluence/display/cplusplus/DCL59-CPP.+Do+not+define+an+unnamed+namespace+in+a+header+file )

据说,get_v()在每个翻译单元中引用了不同的变量,所以它违反了ODR.

这个答案:内联函数和外部链接说内联放松ODR了所以我不确定为什么这仍然是一个错误?

ODR如果这是违规行为,有人可以将我链接到标准中指定的位置吗?

标签: c++language-lawyerlinkageone-definition-ruleinline-functions

解决方案


一个inline函数允许有多个定义(C++17 [basic.def.odr]/6)。这就是inline可以使用函数来防止 ODR 违规的意义。但是,inline函数的多个定义必须相互一致。具体来说,[basic.def.odr]/6.2 说:

在 的每个定义中D,根据 6.4 查找的相应名称应指在 的定义中定义的实体D,或应指同一实体 [...] [一些例外]

的多个定义get_v引用变量v,但v未定义在内部get_v。因此,要求每个定义get_v引用相同的变量v。情况并非如此,因为每个翻译单元都有不同的v. 因此,违反了 ODR。


推荐阅读