为什么要将类型放在未命名的命名空间中?

Fra*_*ier 9 c++ unnamed-namespace

我理解使用未命名的命名空间来使函数和变量具有内部链接.头文件中不使用未命名的命名空间; 只有源文件.源文件中声明的类型不能在外部使用.那么在未命名的命名空间中放置类型有什么用呢?

请参阅这些链接,其中提到的类型可以放在未命名的命名空间中:

Die*_*ühl 14

你想在哪里放置除了未命名的命名空间之外的本地类型?类型不能具有类似的链接说明符static.如果它们不是公开的,例如,因为它们在标题中声明,则本地类型的名称很可能发生冲突,例如,当两个翻译单元定义具有相同名称的类型时.在这种情况下,您最终会遇到ODR违规.在未命名的命名空间中定义类型可以消除这种可能性.

更具体一点.考虑一下你

// file demo.h
int foo();
double bar();

// file foo.cpp
struct helper { int i; };
int foo() { helper h{}; return h.i; }

// file bar.cpp
struct helper { double d; }
double bar() { helper h{}; return h.d; }

// file main.cpp
#include "demo.h"
int main() {
     return foo() + bar();
}
Run Code Online (Sandbox Code Playgroud)

如果您链接这三个翻译单元,则您与helperfrom foo.cppbar.cpp.的定义不匹配.编译器/链接器不需要检测这些,但程序中使用的每种类型都需要具有一致的定义.违反此约束被称为违反"一个定义规则"(ODR).任何违反ODR规则的行为都会导致未定义的行为.

鉴于评论,似乎需要更有说服力.该标准的相关部分是3.2 [basic.def.odr]第6段:

类类型(第9条),枚举类型(7.2),带内部链接的内联函数(7.1.2),类模板(第14条),非静态函数模板(14.5.6)可以有多个定义,类模板的静态数据成员(14.5.1.3),类模板的成员函数(14.5.1.1),或者在程序中未指定某些模板参数(14.7,14.5.5)的模板特化,前提是每个模板定义出现在不同的翻译单元中,并且定义满足以下要求.鉴于在一个以上的翻译单元中定义了这样一个名为D的实体,那么D的每个定义应由相同的令牌序列组成; 和[...]

存在许多进一步的约束,但"应由相同的令牌序列组成"显然足以排除例如上述演示中的定义是合法的.

  • @FrancisXavier尝试使用一个非平凡的默认构造函数:`struct helper {helper(){std :: cout << __FILE__ <<"\n"; 在不同的文件中定义两个`helper`,从相应文件中的函数构造每个的一个实例,从`main`调用两个函数.编译**而不进行**优化.`helper :: helper()`会有两个符号,因为它是(隐式)内联的,所以会丢掉一个符号.剩下的一个将从两个函数调用(linux x64上的gcc 4.9.2,不保证这种行为). (3认同)
  • 我只是试过这个:我在多个文件的全局命名空间中放置了相同的类声明,但我没有收到任何错误。这些类型似乎被视为翻译单元的本地类型。因此,另外将它们放入未命名的命名空间似乎没有任何价值? (2认同)