代码之家  ›  专栏  ›  技术社区  ›  LcdDrm

重载解析查找命名空间

  •  34
  • LcdDrm  · 技术社区  · 6 年前

    以下代码按预期失败,因为没有重载 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
    }
    

    但是,引入模板化版本的 得到 即使它与函数调用不匹配,也会以某种方式使编译器使用 标准::获取 版本:

    #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 80.0
    • GCC 9.0.0(仍为试验版本)

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

    2 回复  |  直到 6 年前
        1
  •  20
  •   Jans    6 年前

    除非在调用点引入模板函数声明,否则在涉及显式模板参数时不使用ADL。你用的是不合格的形式 get 使用非类型模板参数 0 ,因此需要引入模板函数声明或使用 得到 作为 std::get<0>(ar) .

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

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

    编辑:

    正如@yakk-adam nevraumont在注释中指出的,在没有模板函数声明的情况下,表达式 get<0>(ar) 将被分析为 (get<0)>(ar) ,即作为一系列比较表达式而不是函数调用。

        2
  •  4
  •   T.C. Yksisarvinen    6 年前

    请注意,这在C++ 20中是作为结果而改变的。 P0846R0 . 后面跟一个非限定名 < 普通的非限定查找可以找到一个或多个函数,或者找不到任何函数的标记现在被假定为命名模板和 < 相应地进行分析。