问题描述
假设以下代码:
#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' 未在此范围内声明
所以函数 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 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)
接着说:
对于函数调用中的每个参数类型 T,都有一组零个或多个关联命名空间和一个要考虑的零个或多个相关类的集合.确定命名空间和类的集合完全取决于函数参数的类型(以及任何模板模板参数的命名空间).
并包括以下项目符号:
如果 T 是类类型(包括联合),则其关联的类是:类本身;它所属的类成员,如果有的话;及其直接和间接基类.其关联的命名空间是命名空间其关联类是其中的成员.[...]
下面提供了一个类似的例子来解决你的问题:
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.
这篇关于带有命名空间的编译器的有趣行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!