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 )?
CodePudding user response:
The namespace bar contains declarations for different template functions called foo.
One is template<int M, int N> int foo(S<M>); declared at the end, and there is one for each S<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 (Where 42 is the value of M and N can't be deduced, so it doesn't compile).
Prior to C 20, foo<42>(s) would be interpreted as foo < 42 > (s) ((foo < 42) > s with equivalent bracketing), since the < is not interpreted as a template head because lookup for foo doesn't find a template.
When you add using namespace bar;, lookup for foo finds the template function, so foo<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 foo in the global namespace:
// Only for ADL purposes so `foo` is parsed as a template
template<typename> void foo() = delete;
int main() {
bar::S<> s;
return foo<42>(s) foo<>(s);
}
