C++ argument-dependent lookup 实参依赖查找
C++实参依赖查找英文缩写为ADL,在查找无限定函数(包括对重载运算符的隐式函数调用)时,通常无限定名字查找所考虑的作用域和命名空间之外,还在其各个实参的命名空间中查找这些函数,例如:
namespace ns1
{
template<class T>
void foo(T)
{
std::cout << "ns1::foo" << std::endl;
}
struct X {};
}
ns1::X x;
foo(x); //全局命名空间并没有定义foo,但ADL会继续在实参的命名空间中查找
//因为这个实参的类型是ns1::X,所以会继续在ns1命名空间中查找foo
实参依赖查找使得使用定义于不同命名空间的运算符成为可能,例如
namespace ns1
{
struct X { int32_t value; };
const X operator+(const X &lhs, const X &rhs)
{
return X { lhs.value + rhs.value };
}
}
ns1::X x1{10}, x2{20};
auto x3 = x1 + x2; //等价于 x3 = operator+(x1, x2);
//全局命名空间中没有operator+(const X&, const X&)
//但因为实参属于ns1命名空间,所以ADL会检验ns1命名空间,并找到operator+(const X&, const
ADL 是在泛型代码中为交换两个对象而建立的手法能成立的原因:
using std::swap;
swap(obj1, obj2);
namespace ns1
{
struct Object
{
...
void swap(Object &obj) noexcept;
...
};
void swap(Object &lhs, Object &rhs) noexcept
{
lhs.swap(rhs);
}
}
template<class T>
void foo(T &obj1, T &obj2)
{
using std::swap;
swap(obj1, obj2); //无限定函数(未使用名字空间修饰)
//根据ADL,此swap可以在T所属的命名空间中匹配函数
//若无匹配的函数,将调用标准库版swap(std::swap)
}
int32_t a = 1, b = 2;
Object obj1, obj2;
foo(a, b); //调用的是std::swap
foo(obj1, obj2); //调用的是ns1::swap(Object &lhs, Object &rhs)
参考: