1、实参相依的查找ADL:
当查找一个函数调用表达式中的函数名字时,编译器也会到“包含函数调用实参的类型”的名字空间中检查。
例如:
namespace org_semantics {
class X { .... };
void f ( const X & );
void g ( X * );
X operator + ( const X &, const X &);
class String { .... };
std::ostream operator << ( std::ostream &, const String & );
}
//.....
int g ( org_semantics::X * );
void aFunc( ) {
org_semantics::X a;
f ( a); //调用org_semantics::f
g ( a); //错误,调用具有歧义
a = a + a; //调用org_semantics::operator+
}
普通的查找是不会发现函数org_semantics::f的,因为它被嵌套在一个名字空间内,并且对f的使用需要以该名字空间的名字加以限定。
然而,由于实参a的类型被定义于org_semantics名字空间中,因此,编译器也会到该名字空间中检查候选函数。
本例中,程序员本来以为编译器会发现全局的g,但由于实参的类型是org_sematics::X *,因此该名字空间内的g成了候选函数之一,从而导致这个调用有歧义。
即使对g的调用导致了两个候选函数参与重载解析,::g实际上也并未重载org_sematics::g,因为它们不是声明于同一个作用域中的(参考重载与重写并不同)。
ADL是关于函数如何被调用的一个属性,而重载是关于函数被如何声明的一个属性。
2、可以看到ADL在对重载操作符的中缀调用中发挥作用,例如在aFunc中对operator + 的调用。
在这里,中缀表达式a+a等价于operator+( a,a),ADL将会在org_sematics名字空间中发现重载的operator+。
3、实际上,好多人广泛地应用了ADL但没意识到这点。考虑如下对<iostream>的常见使用:
org_sematics::String name( " Qwan" );
std::cout<<" Hello"<<name;
本例中,对operator<<的第一个使用(即最左边那一个),极有可能调用的是类模版std::basic_ostream的一个成员函数,而第二个则是对位于org_semantics名字空间中重载的operator<<的非成员函数的调用。ADL自动的打理了这些。