根据我的理解:
extern
说明符,变量不会自动定义(默认初始化)。我希望以下内容声明一个变量,然后定义相同的变量:
// Declare ::<unnamed>::my_obj with internal linkage and add my_obj to the
// enclosing namespace scope (the global namespace scope).
namespace { extern int my_obj; }
// Expected: Define the variable declared above.
// Actual: Declare and define a new object, ::my_obj.
int my_obj(42);
相反,它声明了两个不同的对象,并警告我未使用的extern int my_obj
。
为什么第二个my_obj
没有定义第一个my_obj
?不在范围内吗?
答案 0 :(得分:3)
在未命名的命名空间中声明的语句&#34;名称将被添加到封闭的命名空间范围内&#34; 并不意味着未命名的命名空间的成员成为封闭命名空间的成熟成员。此添加由隐式using-directive 执行。这样的添加使这些名称对名称查找可见,但不会为了其他目的而使它们成为封闭名称空间的文字成员。
您的代码中存在的问题与以下代码段中的问题相同
namespace A
{
void foo();
}
using namespace A;
void foo() // <- Defines `::foo`, not `A::foo`
{
}
// `A::foo` remains undefined
尽管事实上我们明确地添加了#34;从A
到全局命名空间的名称,它仍然不意味着我们可以使用非限定名称A::foo
将定义 foo
作为全局命名空间的成员。
为了在上面的示例中定义A::foo
,您仍然必须使用其限定名称A::foo
来引用它。对于未命名的命名空间,由于显而易见的原因,这是不可能的。
P.S。编译器通常使用内部编译器生成的名称将未命名的名称空间实现为名称空间。如果你以某种方式想出一个&#34; hack&#34;要发现该名称,从技术上讲,您可能可以通过在定义中使用限定名称来单独定义my_obj
。但请记住,隐藏的命名空间名称在不同的翻译单元中是不同的,因此在每个翻译单元中生成唯一的my_obj
变量。
答案 1 :(得分:1)
未命名的命名空间不是全局命名空间。它是一个特定的命名空间,只在它出现的翻译单元中可见。
This cppreference page更详细地描述了这一点。
如果您尝试在同一个翻译单元中使用未命名的命名空间中定义的符号 - 只需使用它!它的范围很广。您不需要extern
答案 2 :(得分:0)
来自https://msdn.microsoft.com/en-us/library/2tx32sw2.aspx:
使用extern存储类说明符声明的变量是对在程序的任何源文件中在外部级别定义的具有相同名称的变量的引用。内部extern声明用于使块内的外部变量定义可见。 除非在外部声明,否则使用extern关键字声明的变量仅在声明它的块中可见。
答案 3 :(得分:-1)
由于对象是在名称空间中声明的,因此必须在同一名称空间中定义(或者更确切地说,如果名称在一个名称空间中用作声明而在该名称空间外使用定义,则它指的是两个不同的实体)。它在文件范围内可见并不意味着它是该命名空间的成员;我认为断言 -
在未命名的命名空间中声明的名称将添加到封闭的名称中 命名空间范围
- 并不代表你的想法。
C ++ 11标准说一个未命名的命名空间定义的行为就好像它被替换为:
[inline] namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }
(格式化稍微解释;初始&#34;内联&#34;是可选的,如果出现在未命名的命名空间定义中,则显示。)
那么,你期待这个:
namespace a_name {
extern int a;
}
using namespace a_name;
int a = 4;
...第一次提到a
(在命名空间内)会声明变量,第二次定义它吗? (如果你愿意的话,至少这是一致的。但如果你不这样做,你需要认识到标准明确规定你应该从未命名的命名空间中获得相同的行为。)
我不相信有任何机制可以在一个命名空间中声明成员并为另一个命名空间中的同一成员提供定义,即使该成员在第二个命名空间中可见。
解决以下评论:
extern
导致声明不是定义。我已经删除了extern
没有效果的声明,主要是指链接;由于C ++ 11(包括修订),extern
未在未命名的命名空间中授予外部链接的名称。虽然在C ++ 03中它可能在技术上授予了外部链接,但这只是声明/定义的一个属性;该符号在翻译单元外部仍然不可见,并且对链接器没有特殊的可见性。 extern
对C ++ 03中未命名命名空间成员的重要性显然可归结为该成员作为常量表达式的可用性,如果它是const
- 限定指针。const
时,非外部链接指针也不能用作模板参数(即需要常量表达式的上下文)。它确实无法与GCC编译,但它与Clang和英特尔编译器Icc成功编译。对于三个编译器中的任何一个,在内联命名空间中声明的符号是链接级别的局部符号(例如,可以使用objdump
看到) - 链接器级别的符号可见性与之间没有因果关系产生的错误。extern
- 符合条件的符号如果有,则应具有内部联系
驻留在未命名的命名空间中(具体为:具有的名称
上面没有给出内部链接的命名空间范围与封闭命名空间具有相同的链接,如果它是 - 变量的名称;或者...... )。此外,const
- 具有内部链接的声明变量应该可以在需要常量表达的上下文中使用。通过阅读标准,很少有人认为GCC编译器在这种情况下表现不正确。