为什么ADL无法使用std :: get解析为正确的函数

时间:2017-08-03 20:19:03

标签: c++ tuples c++17 structured-bindings

我正在尝试编写一个模板函数,该函数使用ADL解析get来获取结构/范围(tuple - esque)的成员。

#include <iostream>
#include <utility>
#include <tuple>

int main() {
    auto tup = std::make_tuple(1, 2);
    std::cout << get<0>(tup) << std::endl;
}

我这样做是因为结构化绑定提议(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf§11.5.3)说明了如何使用get从结构中获取元素。它表示非成员get用于从结构中获取元素。

我假设上面的代码会编译,因为ADL会导致在get命名空间中查找std函数(因为它的参数类型为std::tuple<int, int>,这是在std)中,它将被发现。但是,我收到了一个错误。有人可以在这里解释正确的方法,以及为什么上面的代码不起作用?在这种情况下如何强制ADL发生?

3 个答案:

答案 0 :(得分:15)

问题最终是模板:

std::cout << get<0>(tup) << std::endl;
//           ~~~~

此时,编译器并不知道这是一个需要使用ADL查找的函数 - get只是一个名称。因为这个名字本身并没有找到任何东西,所以这将被解释为一个未知的名字,后面跟着小于。要使其生效,您需要一些其他功能模板get可见:

using std::get;
std::cout << get<0>(tup) << std::endl; // now, OK

即使它什么都不做:

template <class T> void get();

int main() {
    auto tup = std::make_tuple(1, 2); 
    std::cout << get<0>(tup) << std::endl;
}

结构化绑定措辞使用依赖于参数的查找显式查找get,因此它不需要从[dcl.struct.bind]获得名为get的已经可见的函数模板:

  

通过类成员访问查找在get的范围内查找 unqualified-id E,如果找到至少一个声明,则初始化程序为{ {1}}。否则,初始值设定项为e.get<i>(),其中get<i>(e)在关联的命名空间中查找。在任何一种情况下,get都被解释为 template-id 。 [注意:不执行普通的非限定查找。 - 结束说明]

笔记是关键。如果我们执行了不合格的查找,我们就会失败。

答案 1 :(得分:12)

参数依赖查找与for function templates where an explicit template argument is given的工作方式不同。

  

虽然即使普通也可以通过ADL解析函数调用   查找找不到任何内容,函数调用函数模板   显式指定的模板参数要求有一个   通过普通查找找到的模板声明(否则,它是   遇到未知名称后跟一个小于的语法错误   字符)

基本上,非限定查找需要有一些方法来查找模板函数。然后,ADL可以启动(因为已知名称get是模板)。 Cppreference给出了一个例子:

namespace N1 {
  struct S {};
  template<int X> void f(S);
}
namespace N2 {
  template<class T> void f(T t);
}
void g(N1::S s) {
  f<3>(s);      // Syntax error (unqualified lookup finds no f)
  N1::f<3>(s);  // OK, qualified lookup finds the template 'f'
  N2::f<3>(s);  // Error: N2::f does not take a non-type parameter
                //        N1::f is not looked up because ADL only works
                //              with unqualified names
  using N2::f;
  f<3>(s); // OK: Unqualified lookup now finds N2::f
           //     then ADL kicks in because this name is unqualified
           //     and finds N1::f
}

结构化绑定是一种特殊情况,启用了ADL。

  

在以下上下文中仅限ADL查找(即查找   仅发生关联的命名空间:

     
      
  • 如果成员查找失败,则由range-for循环执行的非成员函数的查找开始和结束
  •   
  • 从模板实例化角度查找从属名称。
  •   
  • 非成员函数的查找由类似元组的类型的结构化绑定声明执行
  •   

重点增加

答案 2 :(得分:0)

快进C ++ 20

现在,C ++ 20中接受的

p0846r0允许ADL调用带有显式模板参数的模板函数。

因此OP的代码now compiles as is with C++20没有错误!