问题历史: ADL(参数依赖查找),也被称为Koenig查找,首次出现在C++中,以支持运算符重载(特别是用户类型的operator<<和operator>>)。其目的是在混合命名空间和用户类型时,正确查找函数。
问题: 标准的函数查找机制可能会“忽略”在调用点不同命名空间中声明的函数。ADL解决了这个问题:编译器考虑函数参数类型的命名空间,以解析名称。这个机制有时会导致意外的重载选择或模糊性。
解决方案: 当调用函数时,如果参数是来自用户命名空间的对象,编译器会在当前作用域及与参数类型相关的所有命名空间中搜索适当的重载函数。
代码示例:
namespace lib { struct Widget {}; void do_something(const Widget&) { std::cout << "Widget" << std::endl; } } using lib::Widget; void call(const Widget& w) { do_something(w); // do_something通过ADL找到 }
关键特点:
如果在两个命名空间中声明相同名称的函数并传递第二个对象,将调用哪个?
如果参数的命名空间中的函数适合参数,将通过ADL选择该函数:
namespace A { struct S {}; void f(const S&) { std::cout << "A!"; } } namespace B { struct S {}; void f(const S&) { std::cout << "B!"; } } A::S a; B::S b; f(a); // 通过ADL调用A::f f(b); // 通过ADL调用B::f
ADL是否适用于模板函数?
是的,如果模板函数在与参数类型匹配的命名空间中定义,ADL将在使用该类型调用时找到它。
ADL是否适用于函数指针?
不适用,ADL在获取函数指针时(例如,获取其地址)不适用。仅适用于直接调用函数。
项目连接了多个第三方库,每个命名空间都有自己的print()。在主代码中使用了不同类对象的print()。由于ADL,编译器开始“选择”错误命名空间中的函数。
优点:
缺点:
使用限定调用(明确指定命名空间):
lib::do_something(w); // 明确!
优点:
缺点: