提问者:小点点

带有父命名空间的嵌套命名空间中的重载解析


我认为在嵌套命名空间中,作为父(或全局)命名空间一部分的任何东西都被同等地考虑用于重载解析,但这个示例似乎显示了相反的情况。

这很好用:

#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();
}

共1个答案

匿名用户

重点是名称查找,它发生在重载解析之前。

当在名称空间ns中找到名称foo时,名称查找将停止,不会检查进一步的作用域,也不会找到全局的foo。 然后在重载解析中只有一个候选项,int可以隐式地转换为float,最后调用ns::foo(float)

(重点为地雷)

名称查找如下所述检查作用域,直到它找到至少一个任何类型的声明,此时查找停止,不再检查其他作用域。