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.
quux
body to a later position in the code, after all the namesfoo
have been declared. – Simpletonfoo(n::A)
to then
namespace – Shelliquux()
aswrite(std::vector<T>)
andfoo(n::A)
aswrite(n::A)
. I want the vector version in a common header file, to use in the print definitions of other print functions all around the place. – Hexateuchquux()
after yourmain()
function and keep its signature in the same place? – Putridquux
as being defined in a header file. – Hexateuchfoo
into the namespacen
is not an option. Moreover, it does not solve the problem, but rather results inquux<B>
not working either and also removing thefoo(int)
will then also not solve the issue but rather result in an error and template definition (because now then::foo
name is not dependent, because it is a qualified name). – Hexateuchfoo(n::A)
into then
namespace (leavefoo(B)
where it is, that is in the same namespace asB
). Do not make a qualified call tofoo
(i.e. leavefoo(T())
, do not make itn::foo(T())
). That should fix it (assuming that you can movefoo(n::A)
intonamespace n
) – Shellivoid foo(A)
is moved to then
namespace. You should accept his answer. – Shelli