参数依赖查找(ADL,Argument-dependent lookup)
参数依赖查找(Argument-dependent lookup),又称 ADL 或 Koenig 查找,是一组于函数调用表达式查找非限定函数名的规则,包含对重载运算符的隐式函数调用。在通常非限定名称查找所考虑的作用域和命名空间之外,还在其参数的命名空间中查找这些函数。
参数依赖查找使使用定义于不同命名空间的运算符可行。例如:
1 #include <iostream> 2 int main() 3 { 4 std::cout << "Test\n"; // 全局命名空间无 operator<< ,但 ADL 检验 std 命名空间, 5 // 因为左参数在 std 命名空间中 6 // 并找到 std::operator<<(std::ostream&, const char*) 7 operator<<(std::cout, "Test\n"); // 同上,用函数调用记法 8 9 // 然而, 10 std::cout << endl; // 错误: 'endl' 不声明于此命名空间。 11 // 此非对 endl() 的函数调用,故不应用 ADL 12 13 endl(std::cout); // OK :这是函数调用: ADL 检验 std 命名空间, 14 // 因为 endl 的参数在 std ,并找到 std::endl 15 16 (endl)(std::cout); // 错误: 'endl' 不声明于此命名空间。 17 // 子表达式 (endl) 不是函数调用表达式 18 }
细节
首先,若通常非限定查找所生成的集合含有下列任何内容,则不考虑参数依赖查找:
否则,对于每个函数调用表达式中的参数,检验其类型,以确定它将添加到查找的命名空间与类的关联集。
若类与命名空间的关联集中的任何命名空间是内联命名空间,则添加其外围命名空间到集合。
若类与命名空间的关联集中的任何命名空间直接含有内联命名空间,则添加该内联命名空间到集合。
在确定命名空间与类的关联集后,为了进一步的 ADL 处理,忽略此集中所有于类中找到的声明,除了命名空间作用域的友元函数及函数模板,陈述于后述点 2 。
以下列特殊规则,合并普通非限定查找找到的声明集合,与在 ADL 所生成关联集的所有元素中找到的声明集合
注意
因为参数依赖查找,定义于相同命名空间的非成员函数和非成员运算符被认为是该类公开接口的一部分(若它们为 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 能找到全体定义于类或类模板内的友元函数(典型地是重载的运算符),即使它完全不在命名空间层次声明。
1 template<typename T> 2 struct number 3 { 4 number(int); 5 friend number gcd(number x, number y) { return 0; }; // 类模板内的定义 6 }; 7 // 除非提供匹配声明,否则 gcd 是此命名空间的不可见成员(除非通过 ADL ) 8 void g() { 9 number<double> a(3), b(4); 10 a = gcd(a,b); // 找到 gcd ,因为 number<double> 是关联类, 11 // 令 gcd 于其命名空间(全局命名空间)可见 12 // b = gcd(3,4); // 错误: gcd 不可见 13 }
尽管即使普通查找找不到结果,函数调用也能通过 ADL 解决,对带显示指定模板实参的函数模板调用还是要求有普通查找所能找到的模板声明(否则,它会是遇到未知名称后随小于号的语法错误)
1 namespace N1 { 2 struct S {}; 3 template<int X> void f(S); 4 } 5 namespace N2 { 6 template<class T> void f(T t); 7 } 8 void g(N1::S s) { 9 f<3>(s); // 语法错误(无限定查找找不到 f ) 10 N1::f<3>(s); // OK ,有限定查找找到模板 'f' 11 N2::f<3>(s); // 错误: N2::f 不接收非类型模板形参 12 // N1::f 不能被找到,因为 ADL 仅适用于非限定名 13 using N2::f; 14 f<3>(s); // OK :无限定查找现在找到 N2::f 然后 ADL 表态, 15 // 因为此名无限定并找到 N1::f 16 }
下列语境发生仅 ADL 的查找(即仅于关联的命名空间查找):
- 范围 for 循环查找非成员函数
begin
与end
,若成员查找失败 - 从模板实例化点的依赖名查找。
- 结构化绑定声明为类tuple类型查找非成员函数get(c++17起)
示例
2 struct X; 3 struct Y; 4 void f(int); 5 void g(X); 6 } 7 8 namespace B { 9 void f(int i) { 10 f(i); // 调用 B::f (无限递归) 11 } 12 void g(A::X x) { 13 g(x); // 错误:在 B::g (普通查找)与 A::g (参数依赖查找)间歧义 14 } 15 void h(A::Y y) { 16 h(y); // 调用 B::h (无限递归): ADL 检验 A 命名空间 17 // 但找不到 A::h ,故只用来自通常查找的 B::h 18 } 19 }
转载于:https://www.cnblogs.com/zl1991/p/7718718.html
参数依赖查找(ADL,Argument-dependent lookup)相关推荐
- java依赖什么意思,JavaEE中的依赖性——依赖查找
关于依赖性管理我们要介绍的第一个策略就是依赖查找(dependency lookup).这种策略是JavaEE中传统形式的依赖性管理,这里可以看到JavaEE规范中的JNDI(Java Naming ...
- SpringIoc依赖查找-5
1. 依赖查找的今世前生: Spring IoC容器从Java标准中学到了什么? 单一类型依赖查找 JNDI - javax.naming.Context#lookup(javax.naming.Na ...
- Spring 延迟依赖查找Bean
Bean 延迟依赖查找接口 // 一个对象工厂 public interface ObjectFactory<T> {// 返回一个对象T getObject() throws Beans ...
- Spring单一类型依赖查找Bean
单一类型依赖查找接口 - BeanFactory BeanFacotry是spring中比较原始的Factory,BeanFactory是个Factory,也就是IOC容器或对象工厂 根据Bean名称 ...
- Java J2EE中的依赖查找
个人看法:设计依赖查找的设计模式,是为了解耦. 单一类型依赖查找 JNDI javax.naming.Context#lookup JavaBeans java.beans.beancontext.B ...
- Spring高手之路——深入理解与实现IOC依赖查找与依赖注入
本文从xml开始讲解,注解后面给出 文章目录 1. 一个最基本的 IOC 依赖查找实例 2. IOC 的两种实现方式 2.1 依赖查找(Dependency Lookup) 2.2 依赖注入(Depe ...
- 依赖查找和依赖注入的区别
简单来说,依赖查找是主动和手动的依赖查找方式,通常需要依赖容器和标准api去实现:而依赖注入则是手动或自动依赖绑定的方式,无需依赖特定的容器和api. 一.依赖查找 依赖查找(Dependency L ...
- 依赖查找 和 依赖注入
依赖查找 和 依赖注入 这两个词看起来很相似,一到了学术上大家就喜欢玩这种概念性的文字游戏,很无奈,但也没有办法. 首先我们不带任何概念和基础的来看这两个词,仅仅分析词意. 他们文字上的区别就是一个是 ...
- 通过ObjectProvider进行依赖查找
public class ObjectProviderDemo { // @Configuration 是非必须注解public static void main(String[] args) {// ...
最新文章
- Linux 播号上网
- main arguments C语言,IT之家学院:通俗科普C语言main函数的参数
- (一)netty介绍
- linux学习之文件操作
- 导航远峰e路航v700pro刷机包
- 联想黑苹果找不到触摸板_联想s410笔记本安装黑苹果10.11.6成功,功能基本都实现,分享给群里的兄弟们!!!...
- 使用OBS屏幕录制时色彩错误问题解决方案
- 你还把游戏本地化当作是游戏翻译
- C# Teechart Pareto图实现 折线显示百分比,多坐标轴显示等
- centos7+ 安装RabbitMQ
- caniuse-lite is outdated. Please run: npx browserslist@latest --update-db
- H5 - 实现半颗星评分功能
- word怎么拆分表格
- 【31】poisoned TLP导致的MCE问题
- 关于FPN(特征金字塔网络)层间融合的理解
- 生信步骤|转录组测序上游分析:hisat2+samtools+stringtie
- Hive 分区表 分桶表
- LiteCAD参考文档的学习二(命令接口,命名对象之块、块的引用、块的属性、命令接口块的插入、块的复制)
- 一个野生程序员的成长
- 树莓派实现摄像头拍照