查找名称空间的重载解析

时间:2018-11-20 12:55:10

标签: 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
}

但是,引入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
  • C 8.0.0
  • GCC 9.0.0(仍为实验版)

编辑: 我知道ADL。但是,如果ADL使第二个代码起作用,那么为什么在第一部分中却没有呢?

2 个答案:

答案 0 :(得分:20)

当涉及显式模板参数时,除非在调用点引入模板函数声明,否则不使用

ADL。您正在使用非限定形式的get和非类型模板参数0,因此您需要引入模板函数声明或将get的限定版本用作{{1 }}。

以标准语std::get<0>(ar) :(强调我的意思)

  

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

编辑:

正如@Yakk-Adam Nevraumont在评论中指出的,如果不存在模板函数声明,则表达式[temp.arg.explicit]/8将被解析为get<0>(ar),即作为比较表达式的一部分函数调用。

答案 1 :(得分:4)

请注意,由于P0846R0,这在C ++ 20中已更改。现在假定使用不合格名称后跟x <- c(0.1, 0.2, 0.3, 0.2, 0.1, 0.1) df <- as.data.frame(x) df %>% mutate(cumsum = cumsum(x)) 令牌,而普通不合格查找针对该令牌找到一个或多个函数或什么都不找到,则命名模板,并据此对<进行解析。