Difference between explicit specialization and regular functions when overloading a template function
Asked Answered
S

5

14

I'm on a roll today. Here goes n00b question number 7:

What's the difference between explicit specialization and just regular functions when you try to overload a template function?

What's the appropriate situation to use the explicit specialization? I don't quite understand it:

#include <iostream>

template <typename s> void test(s var1);
template <> void test<int>(int var1);

int main(){
    test(1);
    test(1.1);
    test("hello!!");
    return 0;
}

template <typename s> void test(s var1){
    std::cout << var1 << std::endl;
}

template <> void test<int>(int var1){
    std::cout << "int " << var1 << std::endl;
}

As oppose to:

#include <iostream>

template <typename s> void test(s var1);
void test(int var1);

int main(){
    test(1);
    test(1.1);
    test("hello!!");
    return 0;
}

template <typename s> void test(s var1){
    std::cout << var1 << std::endl;
}

void test(int var1){
    std::cout << "int " << var1 << std::endl;
}
Sopor answered 13/5, 2011 at 3:20 Comment(1)
+1, nice question. I often use to think about this sometime ago. :)Kaela
T
6

There really isn't a difference between an explicitly specialized template function and a non-template regular function other than the fact that when the compiler looks for a matching signature type for the function call, it will first pick a non-template function that matches the required signature before trying to instantiating any available template functions that may fulfill the required signature match.

If you are going to declare and define a function inside a header file that is not a template-function though, you will have to declare the function as inline. That is because a template function is not an actual function that is linked with a code module until it is actually instantiated. The linker then throws away that instantiation after compiling the code module. If the linker did not do this, then every time a .cpp file included the header file, the linker would complain about duplicate definitions for a function. Using the inline keyword on a non-template function has a similar effect at the compiler level, in that any time the function is used in a .cpp file, the compiler replaces that function call with the body of the function code from the inline function in the header file, and avoids the overhead of a function call with an associated stack active record setup and clean-up. Therefore the linker won't complain about duplicate definitions for a function.

Timeserver answered 13/5, 2011 at 3:28 Comment(7)
replacing the code? so does that mean the inline function also will get access to the variables of the function that called it?Sopor
@ultimatebuster: No, the inline function does not get access to the variables of the calling function. Check out parashift.com/c++-faq-lite/inline-functions.html for all the details, but the key is that inline is merely a suggestion/request to the compiler that the compiler is free to ignore.Jodhpurs
@ultimatebuster No it does not. That's one of the important differences and reason for preferring inline functions to macros. Scope is still respected and enforced by the compiler.Rip
no ... I don't want to say the complier treats an inline function like a glorified macro, but that's sort of what happens. "Sort-of" in the sense that the code from the function body is basically "expanded in-place" at the point of the inline function call. But unlike a macro, you don't have access to the scope of the calling function though as others have noted. Again, it would be like calling the function, but without having to setup and destroy an activation record on the stack, which can be quite a bit of overhead, especially for simple functions that may only do one or two operations.Timeserver
Rule of thumb is to use non-template function if not absolutely necessary to use explicit specialization because a) it looks nicer, b)it gets picked first?Sopor
If I'm going to make a template out of a function, then I make template specializations ... it just keeps the code cleaner, since I won't have overloaded functions that I have to declare inline in the same header file with the template-functions in order to get the code to compile. On the other-hand, I do not make template-functions just for the sake of making template-functions. So I'd say a good rule of thumbs is that if you don't need a generic function, don't go the template route. On the other-hand, if you've already made your function a template, then go-ahead and specialize it.Timeserver
Finally if you have to have your function inside a code module and not a header file (i.e., inside your .cpp file), then it can't be a template, and it can't be declared inline either. As others have noted, inline functions are generally good for something that might have been a macro ... a short function that you want to avoid the function-call overhead. Leave large functions, unless they need to be templates, for your individual code modules.Timeserver
V
3

A major difference is: Explicit specializations don't participate in overloading at all.

template<typename T> void f(T const&);
template<> void f<char const*>(char const * const&);

Calling with f("hello") will not consider any explicit specializations. It will only take all templates, and deduce their template arguments. The above T will be deduced to char[6], and so the specialization won't be selected.

If you overload the function template instead, you have completely different characteristics.

template<typename T> void f(T const&);
void f(char const * const&);

Calling this, it will select the second function, because both the (char const(&)[6]) parameter of the generated specialization and the (char const * const&) parameter match the argument equally well, but the second function is a non-template function, hence it is preferred eventually.

Vetiver answered 13/5, 2011 at 10:9 Comment(0)
K
3

I'm not an expert, but my experience is to use templates (and specialization) when I want to define different return types. You can't overload the return type of a function.

Kisung answered 21/7, 2012 at 0:12 Comment(0)
B
1

When the compiler comes across a function call, it first looks for a non-template function definiton, then an explicitly specialized template and finally, a template definition whose signature matches with the function call. So, for example, if you have an explicitly defined template and a template, then the complier goes for the explicitly defined template. Therefore, you should use an explicity specialzed template when you want to handle a particular datatype in a different manner from the way the template would have handled it.

Another use for explicit specialization is when you want to "overload" a function that does not take any arguments. You can use explicit specialization to give different definitions to the function to handle different datatypes.

Bite answered 9/12, 2017 at 20:10 Comment(0)
K
0

IMHO, explicit specialization for function template should be used when, you are going to call that function using explicit template argument. e.g.

test<int>(myClass); // no argument for 'int' -> declare test() as template specialization

In other cases, you should always use normal specialization. e.g.

test(10, myClass); // argument 10 is 'int' -> test() should be normal specialized

Technically there is no difference between normal and explicit template specialization of a function. The normal specialized versions are completely independent of template functions.

Kaela answered 13/5, 2011 at 3:31 Comment(2)
I don't see how this answers the question.Streetcar
I have answered, What's the appropriate situation to use the explicit specialization?Kaela

© 2022 - 2024 — McMap. All rights reserved.