命名空间搜索顺序

Namespace search order

本文关键字:顺序 搜索 命名空间      更新时间:2023-10-16

我有两个名称空间,每个名称空间都有一个同名的函数。如果我想从其中一个名称空间调用最匹配的函数。从NamespaceA中的一个函数,如果我调用MyFunction(…),它当然会使用命名空间a中的函数。但是,如果我添加了一个"usingNamespaceB::MyFunction",那么我会期望我描述的行为。然而,我实际看到的是,它总是找到NamespaceB函数,即使我在NamespaceA中。然而,如果我还添加了using::NamespaceA(即使我已经在NamespaceA中了),它的工作方式正如我所期望的那样。下面是一个演示。有人能解释一下这是怎么回事吗?

#include <iostream>
namespace NamespaceA
{
  void DoSomething();
  void MyFunction(int object);
}
namespace NamespaceB
{
  void MyFunction(float object);
}
namespace NamespaceA
{
  void DoSomething()
  {
    using NamespaceA::MyFunction; // Note that without this line the lookup always fins the NamespaceB::MyFunction!
    using NamespaceB::MyFunction;
    MyFunction(1);
    MyFunction(2.0f);
  }
  void MyFunction(int object)
  {
    std::cout << "int: " << object << std::endl;
  }
}
namespace NamespaceB
{
  void MyFunction(float object)
  {
    std::cout << "float: " << object << std::endl;
  }
}
int main(int argc, char *argv[])
{
  NamespaceA::DoSomething();
  return 0;
}

这与程序的不同部分查找名称的顺序有关。对于您提到的情况,它与在封闭命名空间之前搜索函数的顶级块的范围有关。基本上,using声明将该名称带入DoSomething的顶级作用域,并且由于该作用域是在封闭命名空间作用域之前查找的,因此如果在那里找到匹配的函数,则不考虑封闭命名空间范围。

我已经掩饰了很多与你的例子无关的东西(例如,如果参数不是一个内置类型,那么,信不信由你,也可以考虑定义该类型的范围内的名称。关于整个故事,请参阅这里的第3.4节。这很可怕,大约13页来描述所有这些东西;但除非你真的很好奇,否则不要麻烦它,因为大多数东西都在那里,所以它"按照你期望的方式工作",或多或少。该文档不是真正的标准,但实际上是一个经过一些更正的工作草案,所以它基本上是真正的C++标准加上一些错误修复。

我相信名称空间使用与变量相同的作用域规则。因此,如果您有一个本地命名空间,那么在移动到外部作用域之前,将首先在那里进行查找。

对于导入了两个具有相同函数名的名称空间的情况,我不确定规则是什么,但为了清晰起见,应该始终完全限定该场景中的函数调用,而不是依赖于人们可能不熟悉的名称空间语言实现的一些细微差别。

简短回答:本地定义的名称和using声明声明的名称隐藏非本地名称。

详细答案:

你的问题很有趣。我没有为这个问题打开C++98,03,11的标准,但打开了Bjarne Stroustrup的书

命名空间-是一个命名的作用域。使用两种技术可以消除冗余:

  • 使用NS::x创建的同义词;(使用声明)
  • 使用名称空间NS::x为的所有变量创建同义词;(使用指令)

你的问题的答案在这里:

Appendix B 10.1
local definitions, and names defined with using-declaration hides 
the name of a non-local definitions.

相反情况下的奖金:

如果你

using NamespaceA::MyFunction;
using NamespaceB::MyFunction;

更改为

using namespace NamespaceB;

然后你由于下面的文本得到了只调用void MyFunction(int对象)的情况

8.2.8.2
Names explicitly declared in namespace (also made with using declaration)
have priority over the names made available by using directives

要玩的额外代码:

#include <iostream>
// var in global namespace
const char* one = "G_one";
// vars in named namespace
namespace NS1 {
    const char* one = "NS1_one";
    const char* two = "NS1_two";
    const char* three = "NS1_three";
}
namespace NS2 {
    const char* one = "NS2_one";
    const char* two = "NS2_two";
    const char* three = "NS2_three";
}
int main(int argc, char *argv[])
{
    using namespace NS1;       // using-directive
    using namespace NS2;       // using-directive
    // const char* two = "L_two"; // local namespace
    using NS2::two;               // using-declaration
    // C++ rules
    // Local names and names with using-declarations
    // takes precedence over the name of the NS     
    std::cout << "two: " << two << std::endl;
    //std::cout << "three: " << three << std::endl; // ambiguous symbol
    // But the name in global-namespace does not have priority over imported name from namespace
    //std::cout << "one: " << one << std::endl; // ambiguous symbol. Because wGlobal names does not have priority over
    return 0;
}