【问题标题】:Ordinary lookup and hiding [duplicate]普通查找和隐藏[重复]
【发布时间】:2020-11-20 21:47:31
【问题描述】:

以下程序编译(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隐藏了::FooLib::Call&lt;N::S&gt;(); 在声明之后,所以在这里绑定名称Foo 时,隐藏应该是有效的,不是吗?

【问题讨论】:

  • 我不太确定,但经过一番研究:如果Foo 是非依赖的,则在模板定义上下文中执行普通查找和ADL。如果Foo 是依赖的,则在模板定义上下文中执行普通查找,但在实例化点执行 ADL。我们的情况是第二种,因此::Foo是通过普通查找找到的。 Lib::Foo 声明不会隐藏 ::Foo,因为它位于普通查找搜索的上下文之后。有人请确认我的假设,也许在答案中。

标签: c++ language-lawyer name-lookup


【解决方案1】:

在模板中使用的名称的所有非 ADL 查找都来自模板定义,即使在 ADL 可能贡献从实例化上下文中找到的声明的情况下,直到实例化才使用结果。

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

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

【讨论】:

  • 谢谢。你能回答实际问题吗?例如:Lib::Foo 不进行隐藏,因为从函数模板 Call 的定义中找到了名称 Foo 的声明(::Foo)。
  • @Dr.Gut:Lib::Foo 无法在查找中隐藏任何尚未声明的内容,我解释了这里发生的情况。
  • 我想第一句话“All non-ADL lookup for a name defined...”有错字。 “定义”这个词应该是“使用”,不是吗?
  • @Dr.Gut:是的; “定义”这个词一定是从“定义上下文”中爬进来的。编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-15
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多