参数依赖查找(Argument-dependent lookup),又称 ADL 或 Koenig 查找,是一组于函数调用表达式查找非限定函数名的规则,包含对重载运算符的隐式函数调用。在通常非限定名称查找所考虑的作用域和命名空间之外,还在其参数的命名空间中查找这些函数。

参数依赖查找使使用定义于不同命名空间的运算符可行。例如:

 #include <iostream>
int main()
{
std::cout << "Test\n"; // 全局命名空间无 operator<< ,但 ADL 检验 std 命名空间,
// 因为左参数在 std 命名空间中
// 并找到 std::operator<<(std::ostream&, const char*)
operator<<(std::cout, "Test\n"); // 同上,用函数调用记法 // 然而,
std::cout << endl; // 错误: 'endl' 不声明于此命名空间。
// 此非对 endl() 的函数调用,故不应用 ADL endl(std::cout); // OK :这是函数调用: ADL 检验 std 命名空间,
// 因为 endl 的参数在 std ,并找到 std::endl (endl)(std::cout); // 错误: 'endl' 不声明于此命名空间。
// 子表达式 (endl) 不是函数调用表达式
}

细节

首先,若通常非限定查找所生成的集合含有下列任何内容,则不考虑参数依赖查找:

1) 类成员声明
2) 块作用域的函数声明(之非 using 声明者)
3) 任何非函数或函数模板之声明(例如,函数对象或另一变量,其名与正在查找的函数名冲突)

否则,对于每个函数调用表达式中的参数,检验其类型,以确定它将添加到查找的命名空间与类的关联集

1) 对于基础类型参数,命名空间与类的关联集为空集
2) 对于类类型(含联合体)参数,集合由以下组成
a) 类自身
b) 其所有直接与间接基类
c) 若类是另一类的成员,则为该外围类
d) 添加到集合的类的最内层外围命名空间
3) 对于是类模板特化的参数类型,在上述规则外,还检验下列规则,并添加其关联类与命名空间到集合
a) 为类型模板形参提供的所有模板实参类型(跳过非类型模板形参并跳过模板模板形参)
b) 任何模板模板实参是其中成员的命名空间
c) 任何模板模板实参是其中成员的类(若它们恰好是类成员模板)
4) 对于任何枚举类型参数,添加枚举定义于其中的命名空间到集合。若枚举类型是类成员,则添加该类到集合。
5) 对于指向 T 类型指针或指向 T 数组的指针,检验类型 T 并添加其类与命名空间的关联集到集合。
6) 对于函数类型参数,检验函数参数类型与函数返回值类型,并添加其类与命名空间的关联集到集合。
7) 对于指向类 X 成员函数 F 的指针类型参数,检验函数参数类型、函数返回值类型及类 X ,并添加其类与命名空间的关联集到集合。
8) 对于指向类 X 数据成员 T 的指针类型参数,检验成员类型和类型 X ,并添加其类与命名空间的关联集到集合。
9) 若参数是重载函数集的取址表达式(或对函数模板)的名称,则检验重载集中的每个元素,并添加其类与命名空间的关联集到集合。
a) 另外,若重载集为模板 id (带模板实参的模板名)所指名,则检验其所有类型模板实参与模板模板实参(但无非类型模板实参),并添加其类与命名空间的关联集到集合。

若类与命名空间的关联集中的任何命名空间是内联命名空间,则添加其外围命名空间到集合。

若类与命名空间的关联集中的任何命名空间直接含有内联命名空间,则添加该内联命名空间到集合。

在确定命名空间与类的关联集后,为了进一步的 ADL 处理,忽略此集中所有于类中找到的声明,除了命名空间作用域的友元函数及函数模板,陈述于后述点 2 。

以下列特殊规则,合并普通非限定查找找到的声明集合,与在 ADL 所生成关联集的所有元素中找到的声明集合

1) 忽略关联命名空间中的 using 指令
2) 声明于关联类中的命名空间作用域友元函数(及函数模板)通过 ADL 可见,即使它们通过普通查找不可见。
3) 忽略函数与函数模板外的所有名称(与变量不冲突)

注意

因为参数依赖查找,定义于相同命名空间的非成员函数和非成员运算符被认为是该类公开接口的一部分(若它们为 ADL 所找到)[1]

ADL 是为于泛型代码交换二个对象而建立的手法的背后理由:

using std::swap;
swap(obj1, obj2);

因为直接调用 std::swap(obj1, obj2) 不会考虑用户定义的 swap() 函数,它可能定义于与 obj1 或 obj2 类型之定义相同的空间,而仅调用非限定的 swap(obj1, obj2) 会无法调用任何函数,若不提供用户定义重载。特别是 std::iter_swap 与所有其他标准库算法在处理可交换 (Swappable) 类型时使用此手段。

名称查找规则使得在来自 std 命名空间的类型上声明运算符于全局或用户定义命名空间,例如对于 std::vector 或 std::pair 的自定义 operator+ 或 operator>> 不适于实践(除非 vector/pair 的元素类型是用户定义类型,这会添加其命名空间到 ADL )。这种运算符不会从诸如标准库算法的模板实例化查找。进一步细节见依赖名

ADL 能找到全体定义于类或类模板内的友元函数(典型地是重载的运算符),即使它完全不在命名空间层次声明。

 template<typename T>
struct number
{
number(int);
friend number gcd(number x, number y) { return ; }; // 类模板内的定义
};
// 除非提供匹配声明,否则 gcd 是此命名空间的不可见成员(除非通过 ADL )
void g() {
number<double> a(), b();
a = gcd(a,b); // 找到 gcd ,因为 number<double> 是关联类,
// 令 gcd 于其命名空间(全局命名空间)可见
// b = gcd(3,4); // 错误: gcd 不可见
}

尽管即使普通查找找不到结果,函数调用也能通过 ADL 解决,对带显示指定模板实参的函数模板调用还是要求有普通查找所能找到的模板声明(否则,它会是遇到未知名称后随小于号的语法错误)

 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<>(s); // 语法错误(无限定查找找不到 f )
N1::f<>(s); // OK ,有限定查找找到模板 'f'
N2::f<>(s); // 错误: N2::f 不接收非类型模板形参
// N1::f 不能被找到,因为 ADL 仅适用于非限定名
using N2::f;
f<>(s); // OK :无限定查找现在找到 N2::f 然后 ADL 表态,
// 因为此名无限定并找到 N1::f
}

下列语境发生仅 ADL 的查找(即仅于关联的命名空间查找):

  • 范围 for 循环查找非成员函数 begin 与 end ,若成员查找失败
  • 从模板实例化点的依赖名查找
  • 结构化绑定声明为类tuple类型查找非成员函数get(c++17起)

示例

       struct X;
struct Y;
void f(int);
void g(X);
} namespace B {
void f(int i) {
f(i); // 调用 B::f (无限递归)
}
void g(A::X x) {
g(x); // 错误:在 B::g (普通查找)与 A::g (参数依赖查找)间歧义
}
void h(A::Y y) {
h(y); // 调用 B::h (无限递归): ADL 检验 A 命名空间
// 但找不到 A::h ,故只用来自通常查找的 B::h
}
}

参数依赖查找(ADL,Argument-dependent lookup)的更多相关文章

  1. Spring IOC(六)依赖查找

    Spring IOC(六)依赖查找 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring BeanFactory ...

  2. Spring中的依赖查找和依赖注入

    作者:Grey 原文地址: 语雀 博客园 依赖查找 Spring IoC 依赖查找分为以下几种方式 根据 Bean 名称查找 实时查找 延迟查找 根据 Bean 类型查找 单个 Bean 对象 集合 ...

  3. ApiPost自动化测试基础之:接口参数依赖的情景处理

    在<ApiPost环境变量之第1课>里,我们介绍了什么是ApiPost环境变量,并如何定义.使用它. 环境变量.接口参数依赖的处理是ApiPost自动化测试的基础.本文主要讲解接口参数依赖 ...

  4. Spring Ioc 依赖查找

    Spring ioc 有依赖查找和依赖注入,之前不太明白依赖查找是什么意思,翻了一大堆博客看了好多定义也不太清楚 ,后来看了小马哥视频,他通过代码演示,清楚地讲解了什么是 依赖查找以及几种依赖查找的方 ...

  5. 【Spring】IoC容器 - 依赖查找

    前言 上一篇文章已经学习了[IoC的主要实现策略]有2种: 1.依赖查找 2.依赖注入 这里稍加详细的介绍一下依赖查找 1.依赖查找的方式 依赖查找的方式可以以多种维度来划分: 1.按名称/类型/注解 ...

  6. EXCEL查找函数之VLOOKUP,LOOKUP,HLOOKUP

    VLOOKUP是纵向查询函数,VLOOKUP(lookup_value,table_array,col_index_num,range_lookup). 参数                      ...

  7. 关于laravel5.5控制器方法参数依赖注入原理深度解析及问题修复

    在laravel5.5中,可以根据控制器方法的参数类型,自动注入一个实例化对象,极大提升了编程的效率,但是相比较与Java的SpringMVC框架,功能还是有所欠缺,使用起来还是不太方便,主要体现在方 ...

  8. 【转】使用windeployqt.exe进行依赖查找打包

    原文:https://blog.csdn.net/u011822862/article/details/52166940 Qt 官方开发环境使用的动态链接库方式,在发布生成的可执行程序时,需要复制可执 ...

  9. Go 包管理与依赖查找顺序

    目录 1. 规则: 2. 编译时的依赖包查找机制 3.vendor vendor的层级搜索 4. modules 1. 规则: 同一目录下只能存在一个包 目录和目录下源文件的包命名可以不同 当包名与目 ...

随机推荐

  1. BZOJ1002: [FJOI2007]轮状病毒 (DP)

    标准做法似乎应该是计算生成树数量的基尔霍夫矩阵之类的.. 我看到的做法是一个神奇的高精度dp,当然以后这个blahblahblah矩阵还是要搞一下..   参考(抄袭)网址   这个dp的原理就是把环 ...

  2. BZOJ 2612 [Poi2003]Sums(最短路)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2612 [题目大意] 给定a数组,问num能否被表示为a[1]*x[1]+a[2]*x[ ...

  3. 2017-2018-1 JAVA实验站 冲刺 day01

    2017-2018-1 JAVA实验站 冲刺 day01 各个成员在 Alpha 阶段认领的任务 小组成员 分工 任务量 张韵琪 写博客.后期市场推广,营销.打杂.各职能的配合 齐力锋 提供宣传用图. ...

  4. hdu 3507 斜率优化

    我的第一道斜率优化. 就这道题而言,写出原始的方程: dp[i] = min{ dp[j] + (sum[i]-sum[j])2  + M | j in [0,i) } O(n^2)的复杂度肯定超时, ...

  5. [转][Android] ListView中getView的原理+如何在ListView中放置多个item

      ListView 和 Adapter 的基础 工作原理: ListView 针对List中每个item,要求 adapter “给我一个视图” (getView). 一个新的视图被返回并显示 如果 ...

  6. VK Cup 2016 - Qualification Round 1 (Russian-Speaking Only, for VK Cup teams) A. Voting for Photos 水题

    A. Voting for Photos 题目连接: http://www.codeforces.com/contest/637/problem/A Description After celebra ...

  7. 我的jlink破解失败经历

    http://fallenwind.spaces.eepw.com.cn/articles/article/item/59116 标题:我的jlink破解失败经历2009-07-12 01:16:56 ...

  8. weblogic清理缓存后重启

    清理缓存步骤如下: 1.前置条件:停止服务 2.找到下面3个目录,然后将里面的文件删除即可: ……/user_projects/domains/base_domain/servers/AdminSer ...

  9. pytest文档12-skip跳过用例

    前言 pytest.mark.skip可以标记无法在某些平台上运行的测试功能,或者您希望失败的测试功能 skip意味着只有在满足某些条件时才希望测试通过,否则pytest应该跳过运行测试. 常见示例是 ...

  10. SharePoint 2013 本地创建解决方案

    在之前的博客<SharePoint 2013本地开发解决方案以及远程调试>中,我们介绍了如何通过修改注册表,使SharePoint 2013 解决方案可以本地编辑,也提及了即使修改注册表, ...