为什么ADL不解析为正确的函数与std ::得到

问题描述:

我试图编写一个模板函数,使用ADL解决get来获取结构/范围的成员(tuple -esque)。为什么ADL不解析为正确的函数与std ::得到

#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会导致std命名空间来看待为get功能(因为它的参数是std::tuple<int, int>类型,这是在std的),它会被发现。但是,我收到一个错误。有人可以在这里解释正确的方法,以及为什么上面的代码不起作用?在这种情况下,如何迫使ADL发生?

问题最终是模板:

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

此时,编译器不知道这是一个需要t o使用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使用参数相关的查找,所以它避免了需要有一个名为get已经可见函数模板,从[dcl.struct.bind]:

ü通过类成员访问查找,在E的范围内查找nqualified-idget,如果发现至少有一个声明,则初始化程序为e.get<i>()。否则,初始化程序是get<i>(e),其中get在关联的名称空间中查找。在任一情况下,get<i>被解释为模板ID。 [注:普通的不合格查找不执行。 - 尾注]

注意事项是关键。如果我们执行了不合格的查找,那么我们就会失败。

+0

非常有趣!我不知道,引入这个未定义的函数可能会导致其他问题吗?像冲突之类的? – Curious

+0

@Curious它会,如果它最终成为首选。我的意思是,实际上不这样做 - 我只是为了解释目的而放在那里。 – Barry

+0

嗯,有什么办法可以强迫ADL发生?我尝试了'template'关键字,但当然不起作用。 – Curious

参数依赖查找不能以相同的方式工作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-仅查找(即,在仅 相关联的命名空间查找)发生:

  • 非成员的查找函数开始和结束由范围换进行如果成员查找失败,则循环
  • 从模板实例化角度查找相关名称。
  • 非成员函数的查找得到由结构化的绑定声明为元组样类型执行

着重强调

+0

它会工作说'std :: cout (tup)

+0

@DanielH这听起来像*可以*如果有人提出它的工作。它[此刻不工作](https://wandbox.org/permlink/dmG6fVeDQwzHvl6q) – Justin

+0

感谢您的回答。我想接受这两个答案,但因为其他答案包括一个简单解析技术的简单例子。我会接受这一点。 – Curious