友元函数在类中的声明在外围是不可见的
上图所示在外围的C类中声明了两个友元函数,f()和f(C<T> const&)
但是在main()函数中使用时,f()被提示没有找到该函数的声明, 但是f(*p)却找到了函数的声明
这是因为:
第一,C++标准规定友元声明在类中,外围作用域是不可见的
第二,C++可以根据ADL查找规则找到该函数的声明
比如上面的f(*p)的形式参数是C<int> 那么ADL查找的关联集合就会包含
模板C实例化后的C<int>作用域,也就能够找到函数f(C<int> const&);的声明
好,那么问题来了,为什么f()函数不能根据ADL查找到声明,f(*p)就可以?
仔细观察这两个函数,就会发现f()没有参数,但是f(*p)有参数。
ADL查找规则
ADL 全称 Argument-Dependent Lookup
第一,使用此规则的函数必须要有参数
第二,使用此规则的函数名称必须为非受限名称,即名称前面没有显式的出现 ->, ::, . 这三个限定符
如何查找
如果函数名称后面有一个或多个实参表达式,那么ADL将会查找这些实参的 关联类 和 关联名字空间
对于给定的类型,关联类 和 关联名字空间 所组成的集合的准确定义可以通过下列规则来确定:
(1)对于基本类型(int, char等), 该集合为空集
(2)对于指针和数组类型,该集合是所引用类型的关联类和关联名字空间
(3)对于枚举类型,名字空间是名字空间是枚举声明所在的名字空间,对于类成员,关联类是枚举所在的类
(4)对于class(包含联合类型),关联类包括该类本身,他的外围类,直接基类,间接基类。关联名字空间包括每个关联类所在的名字空间。
(5)对于函数类型, 该集合包含所有参数类型和返回类型的关联类和关联名字空间
(6)对于类X的成员指针类型,除了包括成员相关的关联名字空间,关联类,该集合还包括与X相关的关联名字空间和关联类
此外ADL查找会忽略using关键字的名字空间。
自此,ADL会在所有的关联类 和 关联名字空间 依次查找直到找到符合的声明。