【问题标题】:Overload resolution looking into namespaces查看命名空间的重载解决方案
【发布时间】:2018-11-20 12:55:09
【问题描述】:

以下代码按预期失败,因为没有找到 get 的重载。使用std::get会解决问题。

#include <array>

int main()
{
    std::array<int, 2> ar{2,3};
    auto r = get<0>(ar);//fails, get was not declared in this scope
}

然而,引入get 的模板版本,即使它与函数调用不匹配,编译器也会以某种方式使用std::get 版本:

#include <array>

template <typename T>
void get(){};

int main()
{
    std::array<int, 2> ar{2,3};

    auto r = get<0>(ar);//returns 2
}

我找不到解释这一点的标准的任何部分。这是我测试的所有 3 个编译器中的一个错误(可能不是),还是我遗漏了什么?

此行为已在

中进行了测试
  • MSVC 15.9.2
  • Clang 8.0.0
  • GCC 9.0.0(仍是实验版本)

编辑: 我知道 ADL。但是如果 ADL 使第二个代码工作,为什么它不能在第一部分呢?

【问题讨论】:

  • 被 ADL 发现。似乎在不提供该声明的情况下阻止了 ADL,.
  • 我怀疑 ADL。但是,它并没有解释为什么没有 fake-template ADL 就不能工作
  • 或者,只是不要给标准库中已经存在的函数名称。
  • @jfh 糟糕的建议。不要试图解决命名空间已经为您解决的问题。
  • @LcdDrm 作为我自己的练习,我编写了您描述的上述功能。如果你喜欢,我可以和你分享。

标签: c++ overload-resolution


【解决方案1】:

除非您在调用点引入模板函数声明,否则在涉及显式模板参数时不使用 ADL。您正在使用非类型模板参数0 使用非限定形式的get,因此您需要引入模板函数声明或使用get 的限定版本作为std::get&lt;0&gt;(ar)。

用标准语言[temp.arg.explicit]/8:(强调我的)

[ 注意:对于简单的函数名,依赖于参数的查找 (6.4.2) 也适用,即使函数名在调用范围内不可见。这是因为调用仍然具有函数调用 (6.4.1) 的语法形式。 但是,当使用带有显式模板参数的函数模板时,调用不具有正确的语法形式,除非在调用点存在具有该名称的函数模板可见。如果没有这样的名称可见,则该调用在语法上不是格式正确的,并且不适用依赖于参数的查找。如果某些此类名称可见,则应用依赖于参数的查找,并且可以在其他名称空间中找到其他函数模板。

编辑:

正如@Yakk - Adam Nevraumont 在评论中指出的那样,在没有模板函数声明的情况下,表达式get&lt;0&gt;(ar) 将被解析为(get&lt;0)&gt;(ar),即作为一系列比较表达式而不是函数调用.

【讨论】:

  • 这是有道理的。尽管在 GCC 9.0.0 中,void get(); 足以让 ADL 再次工作。如果我正确解释了标准的片段,这是一个编译器错误?
  • 那个版本的 GCC 还在开发中,现在说还为时过早
  • 很好的答案,但我会提到 get&lt;0&gt;(ar) 在没有模板的情况下被解析为:(get&lt;0)&gt;(ar)。这更清楚地说明了为什么模板 get 的存在会产生影响。
【解决方案2】:

请注意,由于P0846R0,这在 C++20 中发生了变化。一个非限定名称后跟一个 &lt; 标记,普通的非限定查找要么找到一个或多个函数,要么什么也没找到,现在假定命名一个模板,并相应地解析 &lt;。

【讨论】:

    猜你喜欢
    • 2020-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    相关资源
    最近更新 更多