普通查找和隐藏

Ordinary lookup and hiding

下面的程序可以编译(live demo),但我不明白,为什么。

namespace N {
    struct S {};
}


void Foo(N::S);


namespace Lib {
    template <class T>
    void Call() { Foo(T{}); }

    void Foo();
}


int main()
{
    Lib::Call<N::S>();
}

Lib::Foo 不应该隐藏 ::Foo 吗? Call 中的 Foo 是依赖名称,依赖名称的评估应该推迟到模板实例化时进行。在这种情况下名称查找如何工作?

在命名空间LibFoo(N::S{})可以在void Foo();的声明之前调用,但是不能在声明之后调用,因为Lib::Foo隐藏了::Foo ]. Lib::Call<N::S>();在声明之后,所以在这里绑定名字Foo的时候,隐藏应该是生效的吧?

对模板中使用的名称的所有 non-ADL 查找都来自模板定义,即使在 ADL 可能起作用的情况下,在实例化之前 使用 结果也是如此从实例化上下文中找到的声明。

你可以从“空间”的角度来考虑这一点——依赖查找的两个部分同时发生在不同的地方(限制它们找到的内容)——或者从“时间”的角度来看——non-dependent-ADL 查找在解析模板时发生,结果被保存并在实例化期间与依赖的 ADL 结果合并。前者是标准描述它的方式(以避免将编译描述为 time-dependent 过程),但后者直观地解释了出于解析目的对依赖名称的处理(因此当 typenametemplate 是必需的)。

这方面的标准规则分散在不同类型名称的几种情况下([temp.res]/1.3, [temp.nondep]/1, and [temp.dep.candidate]/1 在 C++20 中)。