在没有限定条件的命名空间中调用函数

vuk*_*ung 8 c++ namespaces c++11

看一下源代码boost::polygon,我看到了以下主题的许多应用:

#include <iostream>

namespace B {

struct A {
  void foo() const { std::cout << "foo" << std::endl; }
};

void bar(const A &a) { a.foo(); }
void baz() { std::cout << "baz" << std::endl; }

}

int main(int argc, char **argv) {
  B::A a;
  bar(a);
  B::baz(); // simply calling baz() does not work

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

它是如何bar(a)在不额外资格被称为?我原以为只会B::bar(a)编译.

当函数在命名空间内没有参数时,不会发生这种情况.

Jac*_*ack 6

根据ISO C++ 14标准,§3.4.2:

当函数调用中的postfix-expression是非限定id时,可以搜索在通常的非限定查找期间未考虑的其他命名空间,并且在那些命名空间中,可以找到命名空间范围的朋友函数或不可见的函数模板声明.对搜索的这些修改取决于参数的类型(以及模板模板参数,模板参数的命名空间).

和以下:

对于函数调用中的每个参数类型T,存在一组零个或多个关联的命名空间以及要考虑的一组零个或多个关联的类.命名空间和类的集合完全由函数参数的类型决定.

如果T是类类型(包括联合),则其关联的类是:类本身; 它所属的成员,如果有的话; 及其直接和间接基类.其关联的命名空间是其关联类的最内部封闭命名空间.

实际上你甚至可以通过附上函数名来防止这种情况发生:

(bar)(a); // doens't compile
Run Code Online (Sandbox Code Playgroud)

(B::bar)(a); // does compile
Run Code Online (Sandbox Code Playgroud)

还要注意,这仅适用于最里面的命名空间,这意味着在以下情况下,您需要限定命名空间:

namespace B {
   namespace C {
     struct A {};
   }

   void bar(const C::A& a) { ... }
}
Run Code Online (Sandbox Code Playgroud)