Reputation: 36782
I have a couple of namespaces, each with a function template named 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
}
The above produces the following 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&) { }
^~~~
Why is A::func
considered if Wrap
is in the global namespace? Shouldn't B::caller
call B::func
?
Upvotes: 1
Views: 126
Reputation: 36782
ADL doesn't just considered the arguments to the function in the case of a template. Here you have Wrap<A::Widget>
as the argument to B::caller
. Because caller
is in namespace B
, B::func
is obviously considered. The reason for A::func
being considered comes from the below (emphasis added)
N659 6.4.2/(2.2) [basic.lookup.argdep]
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the innermost enclosing namespaces of its associated classes. Furthermore, if T is a class template specialization, its associated namespaces and classes also include: the namespaces and classes associated with the types of the template arguments provided for template type parameters [...]
Because A::Widget
is a template argument to Wrap
, A
is also an associated namespace of Wrap<A::Widget>
This example can be made to compile as expected by preventing ADL by using the qualified name:
template <typename T>
void caller(const T& t) {
B::func(t);
}
or by enclosing the function name in paretheses
template <typename T>
void caller(const T& t) {
(func)(t);
}
Upvotes: 2