I have the following code I compile with C++11. This code is a simplification of a real world usage.
namespace bar {
template<int M = 10>
struct S {
template<int N = M*2>
friend int foo(S) {
return N-M;
}
};
template<int M, int N>
int foo(S<M>);
} /* end of bar */
int main() {
bar::S<> s;
/* OK { using namespace bar; return foo<42>(s) + foo<>(s); } // */
/* NOK { return foo<42>(s) + foo<>(s); } // */
/* NOK { using namespace bar; return bar::foo<42>(s) + bar::foo<>(s); } // */
/* NOK */{ return bar::foo<42>(s) + bar::foo<>(s); } // */
}
My question is: Why does it compile with using namespace bar; with unqualified name lookup (see line with /* OK )? While it does not compile in the variant using qualified name lookup (bar::foo<>()) or unqualified name lookup without using namespace (see lines with /* NOK )?
The namespace
barcontains declarations for different template functions calledfoo.One is
template<int M, int N> int foo(S<M>);declared at the end, and there is one for eachS<M>declared as friend functions.A friend function can only be found via ADL. So when you have
bar::foo<42>(s), you could only possibly be calling the free function (Where42is the value ofMandNcan't be deduced, so it doesn't compile).Prior to C++20,
foo<42>(s)would be interpreted asfoo < 42 > (s)((foo < 42) > swith equivalent bracketing), since the<is not interpreted as a template head because lookup forfoodoesn't find a template.When you add
using namespace bar;, lookup forfoofinds the template function, sofoo<42>(s)gets parsed as a templated function call. This eventually picks the friend function found via ADL during overload resolution.This is fixed by adding a function template
fooin the global namespace: