This is a problem of dependent name lookup.
In the expression overloaded(value);
, the name overloaded
is dependent as per [temp.dep]/1.
As far as I know, in the expression n::overloaded(value)
, the name overloaded
(in the id-expression n::overloaded
) is not dependent.
Dependent name lookup is very peculiar, [temp.dep.res]/1
In resolving dependent names, names from the following sources are considered:
- Declarations that are visible at the point of definition of the template.
- Declarations from namespaces associated with the types of the function arguments both from the instantiation context and from the definition context.
(There's a point of instantiation for function templates at the end of the file, so all declarations from associated namespaces can be found.)
For non-dependent names, the normal lookup rules apply (lookup from the definition context).
Therefore, to find names declared after the definition of the template, they have to be dependent and be found via ADL.
A simple workaround is to introduce another parameter to the function overloaded
or wrap the argument, such that one of the arguments of this function has namespace n
associated:
#include <iostream>
class C {};
namespace n {
struct ADL_helper {};
inline void overloaded(int, ADL_helper = {})
{ std::cout << "n::overloaded(int,..)" << std::endl; }
}
template<typename T> void try_it(T value) {
overloaded(value, n::ADL_helper{});
}
namespace n {
inline void overloaded(C, ADL_helper = {})
{ std::cout << "n::overloaded(C,..)" << std::endl; }
}
int main()
{
try_it(1);
C c;
try_it(c);
}
alternatively:
namespace n {
template < typename T >
struct wrapper { T elem; };
inline void overloaded(wrapper<int>)
{ std::cout << "n::overloaded(wrapper<int>)" << std::endl; }
}
template<typename T> void try_it(T value) {
overloaded(n::wrapper<T>{value});
}
namespace n {
inline void overloaded(wrapper<C>)
{ std::cout << "n::overloaded(wrapper<C>)" << std::endl; }
}