参数依赖查找(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. 规则: 同一目录下只能存在一个包 目录和目录下源文件的包命名可以不同 当包名与目 ...
随机推荐
- Ubuntu 12.04下spark1.0.0 集群搭建(原创)
spark1.0.0新版本的于2014-05-30正式发布啦,新的spark版本带来了很多新的特性,提供了更好的API支持,spark1.0.0增加了Spark SQL组件,增强了标准库(ML.str ...
- python学习一月总结_汇总大牛们的思想_值得收藏
''' 下面是我汇总的我学习一个月python(version:3.3.2)的所有笔记 你可以访问:http://www.python.org获取更多信息 你也可以访问:http://www.cnbl ...
- SCOJ 4423: Necklace polya
4423: Necklace 题目连接: http://acm.scu.edu.cn/soj/problem.action?id=4423 Description baihacker bought a ...
- ROS知识(3)----功能包package编译的两种方式
ROS的包编译有两种方法(我知道的),一种是用rosmake,这种方法简单:另一种是用catkin_make,这种方法更方便包的管理和开发.这两种方法都是先建立工作空间workspace(类似于vs下 ...
- mybatis源码分析(2)-----SqlSession创建
1. 在创建好sqlSessionFactory之后,接着就要配置sqlSession的创建. <bean id="simpleTempalte" class="o ...
- Ubuntu14.04和Tiny6410挂载NFS服务!
我是以root身份登录Ubuntu的: 在Ubuntu上执行 #apt-get install nfs-kernel-server //安装NFS服务 在Ubuntu上执行 #mkdir ...
- 【ajax 提交表单】多种方式的注意事项 ,serialize()的使用
在业务中,可能因为表单内容过于庞大,字段过于繁杂,如果人为去拼接的话 ,需要耗费大量的时间和精力,与此同时,代码看上去也是冗余不堪. 所以,提交表单的时候如果能整个表单数据整体提交,那是非常开心的事情 ...
- pytest文档11-assert断言
前言 断言是写自动化测试基本最重要的一步,一个用例没有断言,就失去了自动化测试的意义了.什么是断言呢? 简单来讲就是实际结果和期望结果去对比,符合预期那就测试pass,不符合预期那就测试 failed ...
- System.Threading.Tasks并发和异步代码使用
main.cs System.Threading.Tasks.Parallel.For(0, 10, i => { TestLock test ...
- 魅族MX4的线控电路图