我认为在嵌套命名空间中,作为父(或全局)命名空间一部分的任何东西都被同等地考虑用于重载解析,但这个示例似乎显示了相反的情况。
这很好用:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
void foo(float) { std::cout << "float\n"; }
namespace NS {
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
对foo(0)
的调用与foo(int)
匹配,因为它是更好的匹配,并且一切都按预期工作。 但是,如果我将foo(float)
的声明移到命名空间中:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
namespace NS {
void foo(float) { std::cout << "float\n"; }
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
对foo(0)
的调用现在调用foo(float)
!
我在https://en.cppreference.com/w/cpp/language/overload_resolution和许多其他类似页面中搜索了一下,以找到解释这一点的规则,但我似乎没有找到它。 有人能不能请解释一下,这是由众多复杂的过载解决规则中的哪一个导致的,还是别的什么原因?
编辑
我刚发现它更奇怪。 即使名称空间内的foo
完全不匹配,它仍然不会使用外部的那个。 这完全无法编译:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
namespace NS {
void foo(float, float) { std::cout << "float\n"; }
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
重点是名称查找,它发生在重载解析之前。
当在名称空间ns
中找到名称foo
时,名称查找将停止,不会检查进一步的作用域,也不会找到全局的foo
。 然后在重载解析中只有一个候选项,int
可以隐式地转换为float
,最后调用ns::foo(float)
。
(重点为地雷)
名称查找如下所述检查作用域,直到它找到至少一个任何类型的声明,此时查找停止,不再检查其他作用域。