参数依赖查找(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 }

细节

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

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

 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399546.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

让你的WordPress主题支持自定义菜单

WordPress 3以后的版本已经支持自定义菜单功能&#xff0c;如果你的主题还不能支持这个功能话&#xff0c;我敢说你的主题Out啦&#xff0c;是不是想再In进来&#xff1f;那就认真继续阅读&#xff0c;让你的WordPress主题支持自定义菜单功能。 啦&#xff0c;是不是想再In进来…

2016 年 ACM/ICPC 青岛区域赛 Problem C Pocky

昨晚乱入学弟的训练赛&#xff0c;想了一下这个题。推导的过程中&#xff0c;加深了对公理化的概率论理解。$\newcommand{\d}{\mathop{}\!\mathrm{d}}$ 解法一 考虑 $ d < L$ 的情形。 \begin{equation*} P(X 1) \frac{d}{L} \end{equation*} \begin{align*} P(X 2) &…

为什么新来的技术很难接手维护一个系统

为什么开发功能变得越来越慢? 某天来一个技术&#xff0c;他跟老板说&#xff1a;这个系统太臃肿了。很乱&#xff0c;我很难开展工作下去&#xff0c;至少很难按照我的经验和设想来实施。如果想让我顺利干下去&#xff0c;办法就是对系统进行重构一次(重构代码,或者开发新的系…

Warning: mysqli::__construct(): php_network_getaddresses: getaddrinfo failed:

原来数据库的配置是这样的 DB_CONNECTIONmysql DB_HOSTlocalhost DB_PORT3306 修改成如下&#xff1a; DB_CONNECTIONmysql DB_HOST127.0.0.1 DB_PORT3306 再次执行OK:

ztree 获取当前选中节点的子节点集合

功能&#xff1a;获取当前选中节点的子节点id集合。 步骤&#xff1a;1.获取当前节点 2.用ztree的方法transformToArray()获取当前选中节点&#xff08;含选中节点&#xff09;的子节点对象集合。 3.遍历集合&#xff0c;取出需要的值。 treeNode&#x…

Project facet Dynamic Web Module version 3.1 is not supported.

修改Web Module version 3.1 is not supported.问题 http://uule.iteye.com/blog/2052680 <host id"localhost" root-directory"${resin.root}/webapps/15newIIMS"> <web-app id"/" document-directory""><path-mappin…

不用第三方插件如何统计自己wordpress的访问量

很多wordpress博主都很在乎自己的访问量&#xff0c;使用第三方统计插件又会拖慢自己博客的响应速度&#xff0c;下面就交给大家如何自己写代码统计自己博客的访问量。 工具/原料 wordpress站点 自己站点的各种权限 方法/步骤 登录自己博客的后台&#xff0c;输入正确的用户…

笔记本安装win7和arch linux双系统+xfce4桌面

参考&#xff1a;Archlinux 2015.07.01 和 Windows7 双系统 安装教程http://www.cnblogs.com/fangying7/p/3803290.html 关于Archlinux 的安装 http://blog.csdn.net/ispeller/article/details/9327389 Archlinux安装和使用技巧 http://www.cnblogs.com/vachester/p/5635819.ht…

该Tiled地图制作拿到项目~~这是偷懒,为了直接复制后写来

1.现在&#xff0c;.h声明private:cocos2d::CCSprite* ninja;cocos2d::CCTMXTiledMap* tileMap; 然后.cpp中增加tileMap CCTMXTiledMap::create("MyTileMap.tmx");CCTMXLayer* backLayer tileMap->layerNamed("Tile Layer 1");CCAssert(backLayer, &…

用1、2、2、3、4、5这六个数字,用java写一个main函数,打印出所有不同的排列,如:512234、412345等,要求:4不能在第三位,3与5不能相连。...

最近在看算法&#xff0c;看到这个题&#xff0c;觉得挺经典的&#xff0c;收起。 分析&#xff1a; 1 、把问题归结为图结构的遍历问题。实际上6个数字就是六个结点&#xff0c;把六个结点连接成无向连通图&#xff0c;对于每一个结点求这个图形的遍历路径&#xff0c;所有结点…

WordPress导航菜单函数register_nav_menus() 和 wp_nav_menu()

导航菜单是每一个WordPress主题必须的元素&#xff0c;如果你要制作一个WordPress主题&#xff0c;那就必须熟悉WordPress导航菜单注册函数 register_nav_menus() 和 导航菜单调用函数wp_nav_menu() &#xff0c;这两个参数一般都是配合使用的。今天我们就一起来解释一下这两个…

LeetCode 16 3Sum Closest(最接近的3个数的和)

翻译 给定一个有n个整数的数组S&#xff0c;找出S中3个数&#xff0c;使其和等于一个给定的数&#xff0c;target。返回这3个数的和&#xff0c;你可以假定每个输入都有且只有一个结果。例如&#xff0c;给定S {-1 2 1 -4}&#xff0c;和target 1。那么最接近target的和是2。…

基因重组

1s / 32M 【问题描述】目前,科学家们正致力于对生物基因的重组进行深入研究。基因的物质载体是脱氧核糖核酸(DNA)。DNA 是一种仅由 A、T、G、C 四种基元构成的双螺旋结构的有机分子。DNA 的两条单链上,同一位置的两个基元是互相对应的。A 对 T,G 对 C,因此,我们只需用任意一条链…

Ubuntu下apache2启动、停止、重启、配置

Linux系统为Ubuntu 一、Start Apache 2 Server /启动apache服务 # /etc/init.d/apache2 start or $ sudo /etc/init.d/apache2 start 二、 Restart Apache 2 Server /重启apache服务 # /etc/init.d/apache2 restart or $ sudo /etc/init.d/apache2 restart 三、Stop Apache 2 …

day6笔记

一、上节回顾 list&#xff1a;li [1,2,3,5,a]增加&#xff1a;append&#xff1a;末尾加入追加 insert&#xff1a;插入&#xff0c;在任意位置&#xff0c;insert&#xff08;index,内容&#xff09; extend:迭代着加入&#xff0c;asc ----> ‘a’,‘s’,‘c’ [1,2,3] …

Android手游《》斗地主完整的源代码(支持单机和网络对战)

Android手游《斗地主》完整的源代码&#xff08;支持单机和网络对战&#xff09;下载。一个很不错的源代码。斗地主掌游是一个独特的国内社会斗地主棋牌游戏&#xff0c;之后玩家可以下载网上斗地主和全世界。掌游斗地主特点&#xff1a;1、只有一个主要的社会斗地主棋牌游戏。…

昨天的补给

2014-04-22 09:37 昨天主要改变了之前的布局。采用的是单选按钮。避免逻辑上需要判断。 2014-04-22 09:38 晚上给媳妇买了奶茶和德芙&#xff0c;她很开心。网易订购的项链到了&#xff0c;就是定制的文字多了&#xff0c;不是太好看。 转载于:https://www.cnblogs.com/jsRunne…

jQuery判断当前点击的是第几个li的代码

使用$(this).index()取得li的下标&#xff0c;下面是一个样式替换的例子&#xff1a; $("#aa li").click(function(){ $("#aa li").removeClass("class名字&#xff0c;多个class用空格分开"); $(this).addClass("class名字&#xff0c;多个…

条款46:需要类型转换的时候请为模板定义非成员函数

看看下面这个例子&#xff1a; 1 template<typename T>2 class Rational{3 public:4 Rational(const T & numerator, const T & denominator);5 const T numerator()const;6 const T denominator() const;7 };8 template<typename T>9 const R…

Wordpress菜单函数wp_nav_menu各参数详解及示例

https://blog.csdn.net/qq_37296622/article/details/82633833 注册菜单 首先要注册菜单&#xff0c;将以下函数添加至function.php函数里 register_nav_menus(array( PrimaryMenu>导航, friendlinks>友情链接, footer_nav>页脚导航)); add_theme_support(nav_menus)…