使用命名空间foo时,为什么不能在sub :: bar中使用foo :: bar函数?

时间:2019-02-15 11:00:51

标签: c++ scope namespaces language-lawyer namespace-scope

考虑以下程序:

namespace foo {
namespace sub {
int f();
} // namespace sub 
} // namespace foo 

namespace bar {
namespace sub {

int g()  {
    using namespace foo;
    return sub::f() + 1;
}

} // namespace sub 
} // namespace bar 

我希望它可以编译,但是-它不会:

$ g++-6 -c a.cpp
a.cpp: In function ‘int bar::sub::g()’:
a.cpp:12:9: error: ‘f’ is not a member of ‘bar::sub’
  return sub::f() + 1;
         ^~~
a.cpp:12:9: note: suggested alternative:
a.cpp:3:5: note:   ‘foo::sub::f’
 int f();
     ^

也没有碰运气:

$ clang++-6.0 -c a.cpp
a.cpp:12:9: error: no member named 'f' in namespace 'bar::sub'; did you mean 'foo::sub::f'?
        return sub::f() + 1; 
               ^~~~~~
               foo::sub::f
a.cpp:3:5: note: 'foo::sub::f' declared here
int f();
    ^
1 error generated.

也知道我想要哪个功能!

现在,我了解到,如果我在此处同时拥有foo::sub::fbar::sub::f,事情可能会变得模棱两可。但是-即使我明确要求使用bar::sub函数,为什么foo::sub仍“隐藏” foo::sub

要弄清楚答案可能是什么:

  • 解释为什么这是(最)合理的行为,而我的期望是不合理的。
  • 在C ++标准中采用这种方式的理由。
  • 标准语录中有这种说法。也许上下文可以帮助我理解为什么要这样做。

动机:我已经编写了代码,因此该函数之前的最后一个名称空间是方法名称的一部分,从某种意义上来说,如果不添加名称空间,您将无法理解该功能的作用。因此,我不想像sub_f()那样说C,而是想说sub::f()。实践证明,如果不添加更长的名称空间路径,则很难做到这一点。

3 个答案:

答案 0 :(得分:5)

[namespace.udir]说(强调我):

  

-2- using-directive 指定使用命名空间中的名称可以在 using-directive 之后出现的范围内使用。使用指令。 在不限定名称的查找(6.4.1)中,名称出现   就像在包含 using-directive 和指定的命名空间的最近的封闭命名空间中声明它们一样。 [注意:在这种情况下,“包含”表示“直接或间接包含”。 —尾注]

在您的示例中,“提名的命名空间中的名称”仅为foo::sub,因为这是在命名空间foo中声明的唯一名称,以及“最近封闭的命名空间,其中同时包含 using-指令和指定的名称空间”是全局名称空间。因此foo::sub出现(出于名称查找的目的)就像在全局名称空间中一样,

namespace sub {
int f();
} // namespace sub 

namespace bar {
namespace sub {

int g()  {
    return sub::f() + 1;
}

} // namespace sub 
} // namespace bar 

现在更明显的是sub::f将找不到任何东西。 sub::f的名称查找始于寻找sub。它在封闭的命名空间(bar::sub)中找不到它,因此它在下一个最里面的封闭范围(bar)中查找,并在其中找到sub。到那时,对sub的名称查找停止了,它没有在全局命名空间中查找它将发现{<1> using-directive 可见的foo::sub

下一步,名称查找尝试在为f找到的范围内找到sub,但是在找到的命名空间中没有f,因此名称查找失败。

使用指令的工作方式不同于为名称空间的每个成员添加一个使用声明,它们比使用声明“更弱”。这样做的原因是,在名称空间中真正声明的名称优先于使用指令简单可见的名称。 rodrigo's answer对一个相关问题进行了更详细的说明。

答案 1 :(得分:1)

我认为该标准中阻止您尝试执行的操作的相关部分是:

  

6.3.10隐藏名称[basic.scope.hiding]
  ...
  4在查找由名称空间名称限定的名称期间,声明可能会被using-directive可见,而在包含using-directive < / em>;

您在subfoo命名空间中都拥有bar。尽管有sub指令,但bar中的sub仍在foo中隐藏了using。这就是f()中的foo::sub也不可见的原因。

答案 2 :(得分:0)

第一个问题的答案:
将以下内容添加到程序中会发生什么:

namespace sub
{
    int f();
}

编译器现在应该选择什么:  :: sub :: f()或(使用:: foo::) sub :: f()吗?