Consider the following code:
#include <stdio.h>
namespace Foo {
template <typename T>
void foo(T *, int) { puts("T"); }
template <typename T>
struct foo_fun {
static void fun() { foo((T *)0, 0); };
};
}
namespace Foo {
void foo(int *, int) { puts("int"); }
}
using namespace Foo;
int main() {
foo_fun<int> fun;
fun.fun();
}
What's the expected output? "T" or int?
One compiler (gcc 4.0.1 from Apple's Xcode 3.1.2) output "int", two other compilers (gcc 4.1.2 and 4.1.3) output "T".
If I move foo(int *, int) declaration/definition before the foo(T *, int) version, all output "int". Is the order of overloading/specialization in this case defined by the current standard?
The second void foo(...
is an overload (and not a specialization) which is not visible at the definition of foo_fun::fun
so it won't be found in the context of the template definition. Because T*
is a dependent type, resolution of foo
in the expression foo((T*)0, 0)
will be delayed until template instantiation time and the context of the instantiation will also be considered. However, 14.6.4.2 of the standard says that if the function name is an unqualified-id but not a template-id then for non-ADL lookup only functions visible at the point of definition of the template are considered. There are no function arguments from the Foo
namespace so no argument dependent lookup occurs, hence the template version of foo
is called and not the non-template overload.
Many thanks to litb for the corrections to this answer.
If you made it a specialization as below, then as specializations are chosen at template instantiation time, the specialization can be called so long as the relevant specialization is visible at the point at which the function template is first instantiated for int
.
namespace Foo {
template<>
void foo<int>(int *, int) { puts("int"); }
}
Chapter 14 of the current standard, but it's not very readable :)
Edit: If I had to pick the most relevant part of the standard it would probably be 14.6 [temp.res] para 9. (Slightly abbreviated) If a name does not depend on a template-parameter, a declaration for that name shall be in scope at the point at where the name appears in the template definition; the name is bound to the declaration found at that point and this binding is not affected by declarations that are visible at the point of instantiation.
Edit, edit: But you also need to take into account 14.6.4.2 [temp.dep.candidate]. It is very difficult and dangerous to try and reference the standard because of all the interdependencies, this answer is a case in point.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With