参数依赖查找(ADL,Argument-dependent lookup)
参数依赖查找(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) 不是函数调用表达式
}
细节
首先,若通常非限定查找所生成的集合含有下列任何内容,则不考虑参数依赖查找:
否则,对于每个函数调用表达式中的参数,检验其类型,以确定它将添加到查找的命名空间与类的关联集。
若类与命名空间的关联集中的任何命名空间是内联命名空间,则添加其外围命名空间到集合。
若类与命名空间的关联集中的任何命名空间直接含有内联命名空间,则添加该内联命名空间到集合。
在确定命名空间与类的关联集后,为了进一步的 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 能找到全体定义于类或类模板内的友元函数(典型地是重载的运算符),即使它完全不在命名空间层次声明。
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 的查找(即仅于关联的命名空间查找):
示例
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)的更多相关文章
- Spring IOC(六)依赖查找
Spring IOC(六)依赖查找 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring BeanFactory ...
- Spring中的依赖查找和依赖注入
作者:Grey 原文地址: 语雀 博客园 依赖查找 Spring IoC 依赖查找分为以下几种方式 根据 Bean 名称查找 实时查找 延迟查找 根据 Bean 类型查找 单个 Bean 对象 集合 ...
- ApiPost自动化测试基础之:接口参数依赖的情景处理
在<ApiPost环境变量之第1课>里,我们介绍了什么是ApiPost环境变量,并如何定义.使用它. 环境变量.接口参数依赖的处理是ApiPost自动化测试的基础.本文主要讲解接口参数依赖 ...
- Spring Ioc 依赖查找
Spring ioc 有依赖查找和依赖注入,之前不太明白依赖查找是什么意思,翻了一大堆博客看了好多定义也不太清楚 ,后来看了小马哥视频,他通过代码演示,清楚地讲解了什么是 依赖查找以及几种依赖查找的方 ...
- 【Spring】IoC容器 - 依赖查找
前言 上一篇文章已经学习了[IoC的主要实现策略]有2种: 1.依赖查找 2.依赖注入 这里稍加详细的介绍一下依赖查找 1.依赖查找的方式 依赖查找的方式可以以多种维度来划分: 1.按名称/类型/注解 ...
- EXCEL查找函数之VLOOKUP,LOOKUP,HLOOKUP
VLOOKUP是纵向查询函数,VLOOKUP(lookup_value,table_array,col_index_num,range_lookup). 参数 ...
- 关于laravel5.5控制器方法参数依赖注入原理深度解析及问题修复
在laravel5.5中,可以根据控制器方法的参数类型,自动注入一个实例化对象,极大提升了编程的效率,但是相比较与Java的SpringMVC框架,功能还是有所欠缺,使用起来还是不太方便,主要体现在方 ...
- 【转】使用windeployqt.exe进行依赖查找打包
原文:https://blog.csdn.net/u011822862/article/details/52166940 Qt 官方开发环境使用的动态链接库方式,在发布生成的可执行程序时,需要复制可执 ...
- Go 包管理与依赖查找顺序
目录 1. 规则: 2. 编译时的依赖包查找机制 3.vendor vendor的层级搜索 4. modules 1. 规则: 同一目录下只能存在一个包 目录和目录下源文件的包命名可以不同 当包名与目 ...
随机推荐
- HDU 6136 Death Podracing(循环链表)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6136 [题目大意] 一堆人在操场上跑步,他们都有一定的速度和初始位置, 当两个人相遇的时候编号较小 ...
- linux下使用crontab创建定时任务
在linux中启动crontab服务: /etc/init.d/crond start crontab的命令格式 crontab -l 显示当前的crontab 文件(默认编写的crontab文件会保 ...
- 使用代码配置 NHibernate
多数情况下 NHibernate 使用配置文件进行配置, 但是我们也可以使用代码进行配置, 步骤如下: 1. 创建一个 Configuration using Nhibernate.cfg; var ...
- 简化delegate写法
标准的写法 空 简化后的宏 /**************************************************************/ // delegate 托付 /* #de ...
- ClientDataSet的版本兼容性
ClientDataSet的版本兼容性 在Delphi的早期版本中,Data这个Variant类型的值内部使用的是AnsiString来存贮的字节流,但我并不确定Delphi从什么时候开始,将其改为了 ...
- 设计原则:小议 SPI 和 API
背景 第一次听说 SPI 是阅读<软件框架设计的艺术>,以后陆续在 Log4Net 和 Quartz.Net中发现了以这种形式组织代码的方式,本位给出为什么要区分 SPI 和 API 的一 ...
- python的threading.Thread线程的start、run、join、setDaemon
Pycharm整体看下Thread类的内容:模拟的是Java的线程模型 表示方法method,上面的锁头表示这个是类内部的方法,从方法名字命名规范可以看出,都是_和__开头的,一个下划线表示是子类可以 ...
- go语言基础之有参有返回值函数的使用
1.有参有返回值函数的使用 示例1: package main //必须 import "fmt" //go官方推荐写法 func MaxAndMin(a, b int) (max ...
- windows10 phantomjs 安装和使用
1.下载phantomjs和 Casper phantomjs下载地址:http://phantomjs.org/download.html Casper下载地址:http://casperjs.or ...
- android4.0 USB Camera实例(三)UVC
前面我写了两篇文章说明了zc301的实现 详细请看 http://blog.csdn.net/hclydao/article/details/21235919 以下顺便把通用的USB也写上 前面的ZC ...