Consider the following C++ code example:
namespace n
{
struct A {};
}
struct B {};
void foo(int) {}
template<typename T>
void quux()
{
foo(T());
}
void foo(n::A) {}
void foo(B) {}
int main()
{
quux<n::A>(); // Error (but works if you comment out the foo(int) declaration)
quux<B>(); // Works
return 0;
}
As indicated in the comment, the template instantiation quux<n::A>() causes a compiler error (on GCC 4.6.3):
foo.cpp: In function ‘void quux() [with T = n::A]’:
foo.cpp:22:16: instantiated from here
foo.cpp:13:5: error: cannot convert ‘n::A’ to ‘int’ for argument ‘1’ to ‘void foo(int)’
Can someone explain to me what is going on? I would have expected for it to work the same as with quux<B>(). It must have something to do with when foo is considered dependent. Unfortunately my C++ foo is not good enough. The example compiles fine, when the foo(int) declaration is not present, which is also surprising to me.
Any hints, explanations and workarounds are welcome.
Update 1:
I do not want to (read cannot) move the declaration of foo(n::A) before the definition of quux (which would avoid the error).
Update 2:
Thanks for David for pointing out the related question Template function call confused by function with wrong signature declared before template. The accepted answer by Johannes Schaub – litb proposes a wrapper class solution, that would also work in my case as a workaround. However, I’m not 100% happy with it.
Update 3:
I solved the issue by putting the definition of foo(n::A) in namespace n. Thanks for the helpful answers of Jesse Good and bames53 that not only point out the relevant sections of the standard, but also provide alternative solutions. Thanks to David Rodríguez – dribeas for his explanation when I did not understand the proposed solutions properly and all other contributors.
I think the rule is 14.6.4.2p1:
void foo(n::A) {}is not visible in the template definition context because it comes after andfoois not in the same namespace asn::A. So it needs to be either visible before the template definition or included in the same namespace like below: