具有未命名命名空间的名称空间,声明了相同的变量

时间:2011-12-01 23:28:44

标签: c++ namespaces

我在下面尝试了这个虚拟代码来测试未命名的命名空间。

我有以下输出

 ctor 1
 ctor 0
 3
 5

我对此感到有点困惑。

  1. 我原本期待编译器发出错误,说它无法解决 关于a::m_a的含糊不清。相反,它始终指的是 少嵌套。总是这样吗? C ++遵循什么规则?
  2. 似乎编译器按顺序创建变量CMyObj 写在文件上。总是这样吗?
  3. 有没有办法访问最嵌套的m_a变量 来自main()
  4. 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;
     }
    

4 个答案:

答案 0 :(得分:3)

我没有C ++ 03标准来检查那里的措辞,所以我将引用FDIS n3290。我认为这个问题的答案可以在3.4.3.2/2中的限定名称查找规则中找到:

  

对于名称空间X和名称m,名称空间限定查找集S(X,m)定义如下:设S0(X,m)是X中所有m的声明集和内联名称空间集X(7.3.1)。如果S0(X,m)不为空,则S(X,m)为S0(X,m);否则,S(X,m)是由X中的using指令及其内联命名空间集指定的所有名称空间Ni的S(Ni,m)的并集。

现在,请记住,未命名的命名空间是具有using指令的唯一命名的命名空间。

答案 1 :(得分:1)

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

a::m_b 

在第二个std::cout语句中,编译器会自动替换受损的名称,以便您可以访问它。结合Gene Bushuyev的后续回答:

  

现在,请记住,未命名的命名空间是一个唯一命名的命名空间   使用using指令。

在碰撞名称的情况下,编译器知道a::m_a的含义,因此它使用它。它是命名空间顶层的那个。我认为此时无法找到m_a的未命名命名空间副本。

这个页面在解释命名空间方面做得不错。 Winterdom: On C++ Namespaces

答案 2 :(得分:1)

首先看一下这个简化的代码(以及我的简化说明,你可以阅读§3.4.3.2的详细信息):

namespace a
{
    int x;
}

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

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

namespace a
{
    int x;
}

namespace b
{
    using namespace a;
}

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

此处,它在x中找不到b,因此它搜索命名空间a(因为使用指令)并找到它。现在应该理解为什么这不是模棱两可的:

namespace a
{
    int x;
}

namespace b
{
    using namespace a;
    int x;
}

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

此处它在x中找到b,从不考虑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;
}

与以前一样,x中的b在未考虑未命名的命名空间的情况下被找到。你的代码很相似。

答案 3 :(得分:0)

没有歧义,因为namespace::<unnamed>::m_a的范围是外部命名空间(namespace::a)。无法在主函数中访问namespace::<unnamed>::m_a,这就是没有歧义的原因。尝试编译以下代码,您将收到错误:

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

驻留在同一翻译单元中的全局变量将按其声明的顺序进行初始化。在不同的翻译单元中声明的全局变量的初始化顺序是未定义的。