我有几个名称空间,每个名称空间都有一个名为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&) { }
^~~~
如果A::func
在全局命名空间中,为什么会考虑Wrap
?我不应该B::caller
致电B::func
吗?
答案 0 :(得分:2)
在模板的情况下,ADL并不仅仅考虑函数的参数。在这里,Wrap<A::Widget>
作为B::caller
的参数。由于caller
位于namespace B
,因此显然会考虑B::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);
}
或将函数名称括在paretheses中
template <typename T>
void caller(const T& t) {
(func)(t);
}