Suppose the following:
template <typename T> void foo (T*); // #1
template <typename T> void foo (T); // #2
template <> void foo (int*); // #3
When introducing an explicit specialization of a base template which also has overloads, the specialization is not considered during overload resolution by design. I understand this.
But, given that I could make #3 a non-template overload and it would be then considered for overload resolution, why would I still want to do it as I have done above? Is there a valid use-case for the setup demonstrated above? The only thing I can think of is that if you did not rely on template type deduction, the non-template functions could not be used since they would not accept the <>
syntax when you call them.
BTW I've only reviewed the rules for C++03. I'm not sure if/how C++11 changes these rules/behaviors.
Function overloading is used when multiple functions do similar operations; templates are used when multiple functions do identical operations. Templates provide an advantage when you want to perform the same action on types that can be different.
Template Function Overloading:The name of the function templates are the same but called with different arguments is known as function template overloading. If the function template is with the ordinary template, the name of the function remains the same but the number of parameters differs.
It is possible in C++ to get a special behavior for a particular data type. This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming.
A function template can overload non-template functions of the same name. In this scenario, the compiler first attempts to resolve a function call by using template argument deduction to instantiate the function template with a unique specialization.
Basically, I favor specialization to avoid the principal of least surprise. You want to allow the functions to be called explicitly or non-explicitly to support usage in the widest amount of code possible...and when explicitly instantiated, it should behave the same way as when it was not.
The following template function is an example of how you may want to explicitly select which function you want to call (despite all 3 taking the same argument).
template <typename T> void foo (T*){std::cout << 1 << std::endl;} // #1
template <typename T> void foo (T){std::cout << 2 << std::endl;} // #2
template <> void foo<int> (int* x){std::cout << 3 << std::endl;} // #3
//void foo (int*){std::cout << 3 << std::endl;} // #3
template <typename T>
void bar(void* x) {
foo<T>(reinterpret_cast<T*>(x));
foo<T*>(reinterpret_cast<T*>(x));
foo(reinterpret_cast<T*>(x));
}
int main()
{
cout << "Hello World" << endl;
bar<int>(NULL);
return 0;
}
Without the specialization, this outputs 1,2,3 (the explicitly instantiated call is different than the overloaded call), while with the specialization you get 3,2,3 (the explicit instantiation is the same as the implicit call).
#3
can be used to specialize template functions in one compilation unit without having to update other compilation units.
Let's say we have z.cpp
which looks like this:
template <class T> void foo (T*) { puts("1"); }
template <class T> void foo (T) { puts("2"); }
template <> void foo (int*) { puts("3"); }
void foo(int*) { puts("4"); }
int dummy() {
foo((int*)NULL);
foo<int>((int*)NULL);
foo(4);
foo((long*)NULL);
}
and y.cpp
which looks like this:
#include <stdio.h>
template <class T> void foo (T*);
template <class T> void foo (T);
int main() {
foo((int*)NULL);
foo<int>((int*)NULL);
foo(4);
foo((long*)NULL);
}
The first lines of main will refer to #3
and not #4
. This means that we can specialize foo
for other types in z.cpp
without having to change y.cpp
.
With #4
, you would have to update y.cpp
everytime you added a new overload.
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