Reputation: 981
In the example below, a function template (quartic
) uses an overloaded global function (square
). When compiled, only overloads that are declared before the template itself are considered, so square(int)
is used rather than square(double)
, even though square(double)
is declared before the template is used.
int square(int);
template<typename T>
T quartic(T value) {
return square(square(value));
}
double square(double);
double x(double y) {
return quartic(4.0); // Uses square(int), wanted square(double)
}
Is there a way to make the resolution of which overloaded version of square
depend on what is available when the template is used, so that the user can implement square
for any type T
he uses?
Note: Oddly MSVC will use square(double)
, while GCC, clang and icc uses square(int)
.
Upvotes: 0
Views: 301
Reputation: 1015
the square
in function template quartic
is a dependent name, which means it depends on the template argument T
and its lookup is postponed until T
is known. besides, it's an unqualified name (a qualified name looks like std::cout
), which means it will be looked up in not only its namespace but the namespace of the arguments, which is called argument-dependent lookup, ADL.
so in this case:
obviously, it's not permitted to let your example work by non-ADL lookup. and neither do ADL, because double
is not considered by ADL.
but if the arguments are user-defined type, it works by ADL. more clearly, if you want to call a function defined behind the this scope, you can make that function visible through ADL, which means the function and the arguments' type (or indirect type, see [2]) are in the same namespace.
references:
Upvotes: 5
Reputation: 117168
Only functions declared before quartic
are supposed to be considered, so MSVC does the wrong thing. One possible way to get around this would be to make square
a function template too and let users provide specializations for it.
Your code:
template<typename T> T square(T);
template<typename T>
T quartic(T value) {
return square(square(value));
}
User code:
template<> int square(int value) {
return value * value;
}
template<> double square(double value) {
return value * value;
}
Upvotes: 1