2011-12-01 176 views
7

我试图低于该虚设码来测试未命名的名称空间。命名空间具有相同的变量具名命名空间声明

我有以下的输出

ctor 1 
ctor 0 
3 
5 

我对此感到有点困惑。

  1. 我是在编译器说,它不能解析 歧义关于a::m_a期待一个错误。相反,它始终指向嵌套较少的 。情况总是如此吗? C++遵循什么规则?
  2. 看来,编译器下面写在文件中的顺序 创建变量CMyObj。情况总是如此吗?
  3. 有没有什么办法来访问最嵌套m_a变量 从main()
class CMyObj{  
    public: 
    CMyObj(int a){std::cout << "ctor " << a << std::endl; } 
}; 
namespace a{ 
     namespace{ 
      int m_a=4; 
      int m_b=5; 
      CMyObj m_obj(1); 
     } 
} 
namespace a{ 
     int m_a=3; 
     CMyObj m_obj(0); 
} 
int main(){ 
     std::cout << a::m_a << std::endl; // which one? 
     std::cout << a::m_b << std::endl; // how this is possible? 
     return 0; 
} 

回答

3

我没有C++ 03的标准跟我来检查措辞那里,所以我会从FDIS n3290报价。我认为这个问题的答案在限定的名称查找规则被发现在3.4.3.2/2:

For a namespace X and name m, the namespace-qualified lookup set S(X,m) is defined as follows: Let S0(X,m) be the set of all declarations of m in X and the inline namespace set of X (7.3.1). If S0(X,m) is not empty, S(X,m) is S0(X,m); otherwise, S(X,m) is the union of S(Ni,m) for all namespaces Ni nominated by using-directives in X and its inline namespace set.

现在,请记住具名命名空间是唯一命名的命名空间与使用指令。

+0

最后一句是关键。谢谢。 –

+0

嗨基因!非常感谢您的回放(延迟一段时间)! –

1

我应该花时间找到规范的确切定义,但是当你有一个匿名(未命名)命名空间,编译器实际上产生一个错位的名称。当你写

a::m_b 
第二 std::cout声明

,编译器会自动替换错位的名称,以便您可以访问它。从基因Bushuyev后来的回答内容包括:

Now, remember that unnamed namespace is a uniquely named namespace with a using directive.

在碰撞名称的情况下,编译器知道什么a::m_a手段,所以它使用。它是名称空间顶层的一个。我不认为有什么办法可以到达m_a的未命名名称空间副本。

本页面做了解释命名空间的一份体面的工作。 Winterdom: On C++ Namespaces

+0

“我不认为有什么办法可以到达m_a的未命名名称空间副本。” - 似乎你可以再次打开未命名的名称空间来添加一个存取函数/别名。 – visitor

1

在这个简化的代码首先看(和我简单的解释,你可以阅读§3.4.3.2的细节):

namespace a 
{ 
    int x; 
} 

int main() 
{ 
    int i = a::x; 
} 

考虑,当我们说a::x会发生什么。首先,编译器枚举a中的所有x的声明。如果它发现一个明确的x,它会成功完成。否则,它会递归地搜索由using-directive声明的名称空间。如果它从未发现结果,则该程序不合格。

namespace a 
{ 
    int x; 
} 

namespace b 
{ 
    using namespace a; 
} 

int main() 
{ 
    int i = b::x; 
} 

在这里,它没有找到在bx,所以它搜索名字空间a(因为使用指示符),并发现它。现在应该是有意义为什么这一点也不含糊:

namespace a 
{ 
    int x; 
} 

namespace b 
{ 
    using namespace a; 
    int x; 
} 

int main() 
{ 
    int i = b::x; 
} 

这里找到在bx从不认为a。现在只是考虑到不具名命名空间实际上只是一个具有独特的未知名的命名空间:

namespace b 
{ 
    namespace 
    { 
     int x; 
    } 

    // this is what an unnamed namespace expands to (in exposition) 
    namespace __unique__ {} 
    using namespace __unique__; 

    namespace __unique__ 
    { 
     int x; 
    } 

    int x; 
} 

int main() 
{ 
    int i = b::x; 
} 

像以前一样,在bx不考虑具名命名空间中找到。你的代码很相似。

+0

我喜欢你的详细解释。 –

0

因为namespace::<unnamed>::m_a的范围是外部命名空间(namespace::a),所以没有歧义。在主函数中没有办法访问namespace::<unnamed>::m_a,这就是为什么没有歧义。尝试编译下面的代码,你会得到错误:

namespace ns{ 
    namespace { 
    int a = 2; 
    } 
    int a = 3; 
    int c = a; 
} 

居住在同一个翻译单元的全局变量将在他们声明的顺序进行初始化。在不同翻译单元中声明的全局变量的初始化顺序是未定义的。