查看命名空间的重载决策

Lcd*_*Drm 34 c++ overload-resolution

以下代码按预期失败,因为没有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
}
Run Code Online (Sandbox Code Playgroud)

但是,引入模板化的版本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
}
Run Code Online (Sandbox Code Playgroud)

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

此行为已在测试中

  • MSVC 15.9.2
  • Clang 8.0.0
  • GCC 9.0.0(仍为实验版)

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

Jan*_*ans 20

除非在调用点引入模板函数声明,否则在涉及显式模板参数时不使用ADL.您get使用的是非限定形式的非类型模板参数0,因此您需要引入模板函数声明或使用getas 的限定版本std::get<0>(ar).

在标准中[temp.arg.explicit]/8:(强调我的)

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

编辑:

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

  • 很好的答案,但我会提到`get <0>(ar)`被解析为没有模板:`(get <0)>(ar)`.这使得更清楚为什么模板`get`的存在会产生影响. (5认同)

T.C*_*.C. 6

请注意,由于P0846R0,这在 C++20 中发生了变化。现在假设一个非限定名称后跟一个<标记,普通的非限定查找要么找到一个或多个函数,要么找不到任何内容,以命名模板并进行<相应的解析。