带有命名空间的编译器的有趣行为
假设以下代码:
#include <iostream>
using namespace std;
namespace X
{
class A{};
void f(A a){}
void g(int a){}
}
int main()
{
X::A a;
f(a);
g(5);
}
当我编译代码时,出现以下编译错误:
When I compile the code, the following compile error occurs:
main.cpp:在函数'int main()'中:
main.cpp: 错误: 'g' 未在此范围内声明
main.cpp: In function 'int main()':
main.cpp: error: 'g' was not declared in this scope
所以函数 f
被完美编译,但 g
不是.如何?它们都属于同一个命名空间.编译器是否从 X::A
类型的参数中推断出函数 f
属于 X
命名空间?在这种情况下编译器的行为如何?
So the function f
is compiled perfectly, but g
isn't. How? Both of them belong to the same namespace. Does the compiler deduce that function f
belongs to the X
namespace from the argument of type X::A
? How does compiler behave in such cases?
推荐答案
这适用于函数调用表达式:
This works for the function call expression:
f(a);
因为 X::A
所属的命名空间包含在函数 f
的查找中,原因是 argumentdependent lookup(ADL),cppreference对ADL的解释如下:
because the namespace that X::A
belongs to is included in the lookup for the function f
due to argument dependent lookup(ADL), cppreference explains ADL as follows:
依赖于参数的查找,也称为 ADL 或 Koenig 查找,是用于在函数调用表达式,包括隐式函数调用重载运算符.这些函数名称在除了范围和命名空间之外,它们的参数的命名空间由通常的非限定名称查找考虑.
Argument-dependent lookup, also known as ADL, or Koenig lookup, is the set of rules for looking up the unqualified function names in function-call expressions, including implicit function calls to overloaded operators. These function names are looked up in the namespaces of their arguments in addition to the scopes and namespaces considered by the usual unqualified name lookup.
依赖于参数的查找使使用定义的运算符成为可能在不同的命名空间中
Argument-dependent lookup makes it possible to use operators defined in a different namespace
这在 C++ 标准草案中有所涉及 section 3.4.2
依赖于参数的名称查找:
This is covered in the draft C++ standard section 3.4.2
Argument-dependent name lookup:
当 函数调用 (5.2.2) 中的后缀表达式是非限定 ID 时,不考虑其他命名空间在通常的非限定查找 (3.4.1) 期间,可能会搜索到,并且在这些命名空间中,命名空间范围可能会发现不可见的友元函数或函数模板声明 (11.3)
When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched, and in those namespaces, namespace-scope friend function or function template declarations (11.3) not otherwise visible may be found
接着说:
对于函数调用中的每个参数类型 T,都有一组零个或多个关联命名空间和一个要考虑的零个或多个相关类的集合.确定命名空间和类的集合完全取决于函数参数的类型(以及任何模板模板参数的命名空间).
For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes is determined entirely by the types of the function arguments (and the namespace of any template template argument).
并包括以下项目符号:
如果 T 是类类型(包括联合),则其关联的类是:类本身;它所属的类成员,如果有的话;及其直接和间接基类.其关联的命名空间是命名空间其关联类是其中的成员.[...]
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces of which its associated classes are members.[...]
下面提供了一个类似的例子来解决你的问题:
and further down provides a similar example to your problem:
namespace NS {
class T { };
void f(T);
void g(T, int);
}
NS::T parm;
void g(NS::T, float);
int main() {
f(parm); // OK: calls NS::f
extern void g(NS::T, float);
g(parm, 1); // OK: calls g(NS::T, float)
}
函数调用表达式:
g(5);
不起作用,因为 ADL 不会为基本类型的参数添加任何命名空间.
does not work because ADL does not add any namespaces for arguments that are fundamental types.
Herb Sutter 在 Gotw #30 和 课堂上有什么?- 接口原则.
Herb Sutter covers ADL in Gotw #30 and in What's In a Class? - The Interface Principle.
相关文章