To my surprise this program compiles in both MSCV and GCC:
class A
{
public:
int add() { return 0; }
template<typename T>
T add() { return T(); }
};
int main() {
A a;
a.add();
a.add<int>();
return 0;
}
Obviously, due to the fact that the type of the templated method cannot be deduced and needs to be explicitly stated, so the situation isn't ambigious - still it seems a bit shady - if it were a non-templated method that would be obviously incorrect.
I've tried googling and looking through the last draft of the standard, but couldn't find the answer - is same naming of a template method and a normal method that only differ by return type legal in C++, or are the compilers just being permissive?
This has always been legal C++.
14.5.6/2:
A function template can be overloaded with other function templates and with normal (non-template) functions. A normal function is not related to a function template (i.e., it is never considered to be a specialization), even if it has the same name and type as a potentially generated function template specialization.
When using the "template-id" syntax like add<int>
, only template functions with enough template parameters are considered. So a.add<int>()
doesn't even look at whether the non-template add
matches.
When an identifier names both a plain function and a function template, the compiler will try to deduce template arguments for the function template to get a template function specialization. Then all plain functions and all template function specializations are compared by the usual function overload logic. [See 13.3.1/7.]
In your example, the call a.add()
can't deduce the template argument T
for the template version. So the only viable function is the non-template overload.
There's also another rule that comes up in a similar situation: if a non-template function and a template function specialization would otherwise be an ambiguous overload, the non-template function wins. [This rule is in section 13.3.3, in the middle of the definition of what makes one function better than another for a given set of arguments.]
class B
{
public:
int f(int n) { return n+1; }
template<typename T>
T f(T n) { return n; }
};
int main() {
B b;
b.f(1); // both are viable, non-template wins
b.f<int>(1); // only the template is viable
return 0;
}
This makes sense because the template can still be used by other specializations, or by explicitly using the <
angle brackets>
. So overloading a function template with a non-template function is sort of like adding an explicit specialization, but with fewer headaches.
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