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

Overload resolution in nested namespace with parent namespace

我认为在嵌套的命名空间中,任何属于父(或全局)命名空间的部分都被同等地考虑用于重载解析,但这个例子似乎不是这样。

这很好用:

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

重点是 name lookup,它发生在重载解析之前。

当在命名空间 NS 中找到名称 foo 时,名称查找将停止,不会检查进一步的范围,全局 foo 将不会在全部。然后在重载决策中只有一个候选者,并且 int 可以隐式转换为 float,然后 NS::foo(float) 最后被调用。

(强调我的)

name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.