Explicit specialized functions of templates with overloads: why do you need to do this?

Assume 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 that also has overloads, specialization is not taken into account when resolving design overloads. I understand it.

But, given that I could make # 3 a non-template overload, and then this would be considered to allow overload, why do I still want to do this as I did above? Is there a valid use case for the installation shown above? The only thing I can think of is that if you did not rely on the deduction of the type of the template, functions without templates could not be used, because they did not accept the <> syntax when you called them.

BTW I just looked at the rules for C ++ 03. I'm not sure if these rules / C ++ 11 behavior has changed.

+7
c ++ c ++ 11 templates
source share
2 answers

Basically, I prefer specialization to avoid the least surprise. You want functions to be called explicitly or implicitly in order to support the widest possible use of code ... and when explicitly instantiating it, it should behave just as if it weren’t.

The following template function is an example of how you can explicitly choose which function you want to call (despite the fact that all 3 accept 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 specialization, this yields 1,2,3 (an explicitly invoked call differs from an overloaded call), while by specialization you get 3,2,3 (an explicit instantiation is the same as an implicit invocation).

+1
source share

#3 can be used to specialize template functions in one compilation unit without the need to update other compilation units.

Say we have z.cpp that 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 refer to #3 , not #4 . This means that we can specialize foo for other types in z.cpp without changing y.cpp .

With #4 you will have to update y.cpp every time you add a new overload.

+1
source share

All Articles