为什么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。 [注:普通的不合格查找不执行。 - 尾注]
注意事项是关键。如果我们执行了不合格的查找,那么我们就会失败。
参数依赖查找不能以相同的方式工作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-仅查找(即,在仅 相关联的命名空间查找)发生:
- 非成员的查找函数开始和结束由范围换进行如果成员查找失败,则循环
- 从模板实例化角度查找相关名称。
- 非成员函数的查找得到由结构化的绑定声明为元组样类型执行
着重强调
非常有趣!我不知道,引入这个未定义的函数可能会导致其他问题吗?像冲突之类的? – Curious
@Curious它会,如果它最终成为首选。我的意思是,实际上不这样做 - 我只是为了解释目的而放在那里。 – Barry
嗯,有什么办法可以强迫ADL发生?我尝试了'template'关键字,但当然不起作用。 – Curious