依赖于实参的名字查找依赖于实参的名字查找是C++程序设计语言中的名字查找机制之一。英文为“argument-dependent lookup”,因此缩写为ADL。[1]ADL依据函数调用中的实参的数据类型查找未限定(unqualified)的函数名(或者函数模板名)。这也被称作“克尼格查找”(Koenig lookup),虽然安德鲁·克尼格并不是它的发明者。[2]
语义依赖于实参的名字查找的先决条件如果通常的未限定(unqualified)名字查找所产生的候选集包括下述情形,则不会启动依赖于实参的名字查找:
命名空间与类的相关集合函数调用表达式的每个实参的类型用于确定命名空间与类的相关集合(associated set of namespaces and classes)并用于函数名字查找:[3]
通常的未限定查找发现的结果与ADL查找发现的结果应该合并,并遵从如下特别规则:
例子一个简单示例: namespace NS {
class A {};
void f(A *&, int) {}
}
int main()
{
NS::A *a;
f(a, 0); //calls NS::f
(f)(a,0); //error: NS::f not considered; parentheses prevent argument-dependent lookup
}
更为复杂、精致的例子: namespace N2 { struct DS; }
namespace N1 {
struct S {
void operator+(S) {}
};
template<int X> void f(S) {}
void fDS(N2::DS* v) {}
}
namespace N2 {
struct DS :N1::S {};
template<class T> void f(T t) {}
}
void g() {
N2::DS sv;
fDS(&sv); // sv的类型N2::DS的基类型N1::S所在的命名空间N1的函数N1::fDS
sv+sv; // 调用N1::S::operator+(S)运算符成员函数
}
另一个示例: namespace N1 {
struct S {};
template<int X> void f(S) {}
void bar(S) {}
}
namespace N2 {
template<class T> void f(T t) {}
}
void g(N1::S s) {
bar(s); // lookup N1::bar
// f<3>(s); // Syntax error: unqualified lookup finds no f, so it understands as arithematic expression " f < 3 "
N1::f<3>(s); // OK, qualified lookup finds the template 'f'
// N2::f<3>(s); // Error: N2::f does not take a non-type parameter
// N1::f is not looked up because ADL only works with unqualified names
using N2::f;
f<3>(s); // OK: Unqualified lookup now finds N2::f
// then ADL kicks in because this name is unqualified and finds N1::f
}
关于内联命名空间的示例: namespace ADL{
inline namespace v101 { // 下述代码中,命名空间名字v101都可以忽略
class foo {
public:
class bar { };
};
}
void func1(foo::bar v) {
int i = 101;
}
}
int main()
{
ADL::foo::bar v1;
func1(v1); // lookup to ADL::func1
}
接口ADL能查询到的函数被认为是类的接口之一。标准模板库的几个 C++標準程式庫常见模式是用ADL查找程序声明的重载运算符。例如,下述程序如果没有ADL将无法编译通过:[2] #include<iostream>
int main()
{
string hello = "Hello World, where did operator<<() come from?";
std::cout << hello << std::endl;
}
运算符 批评ADL使得类之外定义的函数就如同类的接口一样被调用,这使得命名空间不是过于严格。例如,C++标准模板库使用未限定的 std::swap(a, b);
的效果可能相同与或不同于 using std::swap;
swap(a, b);
(其中
参考文献
外部链接
|
Portal di Ensiklopedia Dunia