ADL in case of equal-named member function
argument-dependent-lookup, c++, interface, non-member-functions
Solution
As you found out yourself, adding a member function `frobnicate` to the class interface of `Bar` (or `Bar<T>` in the template case), will prevent ADL from finding `foo::frobnicate`.
The easiest -and in this case idiomatic- way to add `frobnicate` functionality to a class `Bar` (or to a class template `Bar<T>`) is to add a non-member function `frobnicate(Bar)` (or function template `frobnicate(Bar<T>)`) to the namespace `bar`
namespace foo {
struct Foo {};
void frobnicate(Foo const &) {}
}
namespace bar {
template<class T>
struct Bar {
T t;
};
template<class T>
void frobnicate(Bar<T> const& b)
{
frobnicate(b.t);
}
}
int main () {
bar::Bar<foo::Foo> x;
frobnicate(x);
frobnicate(foo::Foo());
}
If you insist on having a member function, you will have to rename it to something like `do_frobnicate()`. I would not use type traits tricks to get the same behavior as it is an indirect approach, and makes the class interfaces much harder to understand (remember Stroustrup's motto: "represent your ideas directly in code").
Problem
The situation is that some member function `bar::Bar::frobnicate` wants to utilize ADL to find a function from some unknown namespace, within a function that has an identical name. However, it only finds its own name. Testcase (Note that in reality, `Bar` is a `Foo`-agnostic template; this is just the reproducible, minimal testcase) ``` namespace foo { struct Foo {}; void frobnicate(Foo const &) {} } namespace bar { struct Bar { void frobnicate() { foo::Foo foo; frobnicate(foo); // <-- error } }; } int main () { bar::Bar x; x.frobnicate(); frobnicate(foo::Foo()); } ``` Results in: ``` test.cc: In member function ‘void bar::Bar::frobnicate()’: test.cc:10:31: error: no matching function for call to ‘bar::Bar::frobnicate(foo::Foo&)’ test.cc:10:31: note: candidate is: test.cc:8:18: note: void bar::Bar::frobnicate() test.cc:8:18: note: candidate expects 0 arguments, 1 provided ``` Standard I understand that this is correct compiler behaviour: 3.4.1 Unqualified name lookup [basic.lookup.unqual] (...) name lookup ends as soon as a declaration is found for the name (...) and only after unqualified lookup failed, argument dependent lookup comes into play: 3.4.2 Argument-dependent name lookup [basic.lookup.argdep] When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched Workaround My current workaround is to introduce a special traits class that does not define the clashing name itself: ``` struct BarTraits { void frobnicate_(foo::Foo const &b) { frobnicate(b); } }; ``` or this ligher version: ``` void frobnicate_(foo::Foo const &c) { frobnicate(c); } ``` Question Are there better alternatives than introducing such traits classes? Explicitly qualifying the call as `foo::frobnicate(foo)` is not an option here, because (as mentioned) the `Bar` class is a template upon `Foo` in reality and should not only work for types in the `foo` namespace.