我正在尝试编写一个模板函数,该函数使用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发生?
答案 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-idE
,如果找到至少一个声明,则初始化程序为{ {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)