考虑模板参数的参数相关外观 (ADL)?

Argument Dependent Look (ADL) considering template arguments?

本文关键字:参数 外观 ADL      更新时间:2023-10-16

我有几个命名空间,每个命名空间都有一个名为f的函数模板。

// f() and Widget
namespace A {
struct Widget { };
template <typename T>
void func(const T&) { }
}
// f() and caller()
namespace B {
template <typename T>
void func(const T&) { }
template <typename T>
void caller(const T& t) {
func(t); // error occurs here
}
}
template <typename T>
class Wrap { };
int main() {
Wrap<A::Widget> w{};
B::caller(w); // triggers error
}

以上产生以下错误

error: call of overloaded ‘func(const Wrap<A::Widget>&)’ is ambiguous
func(t);
~~~~^~~
note: candidate: void B::func(const T&) [with T = Wrap<A::Widget>]
void func(const T&) { }
^~~~
note: candidate: void A::func(const T&) [with T = Wrap<A::Widget>]
void func(const T&) { }
^~~~

如果Wrap位于全局命名空间中,为什么会考虑A::funcB::caller不应该打电话给B::func吗?

ADL 不仅在模板的情况下考虑函数的参数。在这里,您将Wrap<A::Widget>作为B::caller的参数。因为callernamespace BB::func显然是被考虑在内。考虑A::func的原因来自以下几点(着重号是后加的)

N659 6.4.2/(2.2) [basic.lookup.argdep]

如果 T 是类类型(包括联合),则其关联的类为:类本身;它所在的类 成员(如有);及其直接和间接基类。其关联的命名空间是最里面的 包含其关联类的命名空间。此外,如果 T 是类模板专用化, 其关联的命名空间和类还包括:与 为模板类型参数提供的模板参数的类型[...]

因为A::Widget是要Wrap的模板参数,所以A也是Wrap<A::Widget>的关联命名空间

此示例可以通过使用限定名阻止 ADL 来按预期进行编译:

template <typename T>    
void caller(const T& t) {    
B::func(t);      
}

或者将函数名称括在 parethes 中

template <typename T>    
void caller(const T& t) {    
(func)(t);      
}