假设以下代码:
#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);
}
编译代码时,会发生以下编译错误:
main.cpp:在函数&#39; int main()&#39;:
main.cpp:错误:&#39; g&#39;未在此范围内声明
所以函数f
编译得很完美,但g
并非如此。怎么样?它们都属于同一名称空间。编译器是否从f
类型的参数中推断出函数X
属于X::A
命名空间?编译器在这种情况下如何表现?
答案 0 :(得分:27)
X::A a;
f(a);
因 Argument-Dependent Lookup (也称为Koenig Lookup)而起作用。 a
是名称空间A
内的类X
的对象,当编译器搜索可匹配的函数f
时,它会查看名称空间X
在这种情况下。有关详细信息,请参阅Argument Dependent Lookup。
答案 1 :(得分:19)
这适用于函数调用表达式:
f(a);
因为X::A
由于argument dependent lookup(ADL)而对f
}函数的查找中包含3.4.2
所属的命名空间,所以cppreference解释 ADL ,如下所示:
依赖于参数的查找,也称为ADL或Koenig查找,是 查找不合格函数名称的规则集 函数调用表达式,包括对函数的隐式函数调用 重载运营商。这些函数名称在中查找 除了作用域和名称空间之外,还有其参数的名称空间 通过通常的非限定名称查找。
依赖于参数的查找可以使用定义的运算符 在不同的命名空间
draft C++ standard部分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)
}
依赖于参数的名称查找中涵盖了这一点:
当函数调用(5.2.2)中的postfix-expression是非限定id时,不考虑其他名称空间 在通常的非限定查找(3.4.1)期间,可以搜索,并在那些命名空间中,命名空间范围 友情功能或功能模板声明(11.3)可能无法看到
继续说:
对于函数调用中的每个参数类型T,有一组零个或多个关联的命名空间和一个 要考虑的零个或多个关联类的集合。确定名称空间和类的集合 完全由函数参数的类型(以及任何模板模板参数的名称空间)。
并包含以下项目符号:
如果T是类类型(包括联合),则其关联的类是:类本身;它所属的类 会员,如果有的话;及其直接和间接基类。 其关联的命名空间是命名空间 其关联类是成员。[...]
并进一步向下提供了与您的问题类似的示例:
g(5);
函数调用表达式:
{{1}}
不起作用,因为 ADL 不会为基本类型的参数添加任何名称空间。
Herb Sutter在Gotw #30和What's In a Class? - The Interface Principle中涵盖了ADL。
答案 2 :(得分:6)