命名空间混乱

Suv*_*yil 5 c++ namespaces

我是命名空间的新手,并且正在尝试使用C++ Primer

#include<iostream>
namespace Jill 
{
 double bucket;
 double fetch;
 struct Hill{ };
}

double fetch;

int main()
{
 using namespace Jill;
 Hill Thrill;
 double water = bucket; 
 //double fetch; //<<<<<<<<<<<<//
 std::cin>> fetch;
 std::cin>> ::fetch;
 std::cin>> Jill::fetch;
 std::cout<<"fetch is "<<fetch;
 std::cout<<"::fetch is "<< ::fetch;
 std::cout<<"Jill::fetch is "<< Jill::fetch;
}

int foom()
{
 Jill::Hill top;
 Jill::Hill crest;
}
Run Code Online (Sandbox Code Playgroud)

当标记的行//<<<<<<<<<<<<//未注释时,我得到预期的结果.即 local变量隐藏globalJill::fetch.但是当我发表评论时,剩下2个.global fetchJill::fetch.编译器会给出错误

namespaceTrial1.cpp:17:13: error: reference to ‘fetch’ is ambiguous
namespaceTrial1.cpp:9:8: error: candidates are: double fetch
namespaceTrial1.cpp:5:9: error:                 double Jill::fetch
namespaceTrial1.cpp:20:26: error: reference to ‘fetch’ is ambiguous
namespaceTrial1.cpp:9:8: error: candidates are: double fetch
namespaceTrial1.cpp:5:9: error:                 double Jill::fetch
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么编译器会混淆这导致歧义?为什么它不承担fetch刚才Jill::fetch,因为我已经添加using namespace Jill在开始main()

如果我using Jill::fetch;在main的开头使用声明,问题就会得到解决.因为using Jill::fetch它就好像它已在该位置声明一样.所以,它就像有一个local fetch变量.[我是否正确?]为什么using declaration表现得好像变量是在该位置声明的并且using directive不是?

Seb*_*edl 3

using 指令修改名称查找的方式对于大多数程序员来说并不完全直观。标准在 [namespace.udir]p2 中这样说:

在非限定名称查找 (3.4.1) 期间,名称看起来就像是在最近的封闭命名空间中声明的,该命名空间同时包含 using 指令和指定命名空间。

这种措辞意味着命名空间中的名称不会出现在当前作用域中,而是出现在某些外部作用域中。在您的示例中,using 指令位于全局命名空间中的函数中,而 Jill 也位于全局命名空间中,因此 Jill 中的名称看起来就像位于全局命名空间中一样。(正如 Joachim 所说,这些名称实际上并未在那里引入,因此它们不会立即与现有名称冲突,并且当您实际使用它们时,您只会得到不明确的查找。)

这是一个简单的情况,编译器会给出一个错误,这很好。实际上可能会变得更复杂。

namespace Outer {
  namespace Mid1 { int i = 1; }
  namespace Mid2 {
    namespace Tricky {
      int i = 2;
      namespace Inner {
        void f() {
          using namespace Mid1;
          std::cout << i;
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

即使您在引用 i 的行旁边有 using 指令,这也会输出 2,而不是 1。Mid1但包含两者和 using 指令的最近的封闭命名空间是Outer,因此Mid1::i其行为就好像它是在 中声明的一样Outer。如果你有一个,Outer::i它就会被 遮蔽Tricky::i,而且Mid1::i票价也好不到哪里去。

一个简单的解决方案是禁止 using 指令并仅使用 using 声明和命名空间别名。它们更加直观。