Why use template specializations? - c++

I wonder why template specializations make sense?
Aren't the following things equivalent?
Template specialization:
template <typename T>
void f(T t) {
something(t);
}
template <>
void f<int>(int t) {
somethingelse(t);
}
Non-template function instead of specialization:
void f(int t) {
somethingelse(t);
}
I believe these are the same because the non-template function will always be preferred.

This is the answer I came up with:
It's different if the template parameter is not a parameter of the function being defined:
template <typename T>
void f() {
T t;
something(t);
}
template <>
void f<int>() {
int t;
somethingelse(t);
}
In this case defining:
void f() {
int t;
somethingelse(t);
}
would make all the template versions unuseable.
Maybe somebody else has better ideas. :)

The question boils down to determining when the specialization will be used that the overload cannot. There are different situations where this is the case although they are uncommon enough, and it is simple enough to make mistakes that the general recommendation is to prefer overloads to specializations.
When the caller explicitly requests the use of a template. In the code example you provide if the call is f<int>(42) or even f<42>(), then the overload will not be used.
When you cannot provide the required overloads, or the overload cannot be resolved at the place of call. For example if the type is not one of the function arguments (it is either not present in the signature at all or only in the return type:
template
T f();
In this case, you cannot provide overloads int f(); and double f(); but you can provide as many template specializations as you need, and it will be up to the user to force the selection of one or the other. Note that this could be considered a subcase of the previous case: because the template arguments take no part in the function arguments, the user needs to provide the template arguments, so the call is explicitly to a template.
When you want to place special constraints on the combination of arguments and inhibit implicit conversions:
template
void f( T, T ); // Both argument must be the same type
Because template argument deduction only perform perfect matches, this template can only be used when both arguments are of the exact same type, if you add an overload void f(int,int) that overload can be used with any combination of types that are implicitly convertible to int, like f( 5, 3.0 ), but the specialization won't.
In general, for most cases, none of the cases above really apply, so an overload should be preferred.
There might be more, but those are the ones I can recall off the top of my head

The way you declare the function does matter if you insist on calling it like f<int>(42). This will find the specialization, but not the overload.
If the call always looks like f(42), either alternative will work.

Function template specialization is deprecated in favor of function overloads with one exception: you are allowed to add a function template specialization to the std namespace, you aren't allowed to add a new function. So, if you need to supply a specific version for something in the std namespace, you have to use template specialization. For instance, to support creating an unordered_map with a user-defined class as the key you have to specialize std::hash for your class.

Related

Specializing template function with empty angle brackets: Does it make a difference without it? [duplicate]

A textbook I have notes that you can provide your own implementation for standard library functions like swap(x,y) via template specialization or function overloading. This would be useful for any types which can benefit from something other than an assignment swap, like STL containers for example (which already have swaps written, I know).
My questions are the following:
What's better: template specialization to give your specialized
swap implementation, or function overloading providing the exact
parameters you wish to use without a template?
Why is it better? Or if they're equal, why is this?
Short story: overload when you can, specialise when you need to.
Long story: C++ treats specialisation and overloads very differently. This is best explained with an example.
template <typename T> void foo(T);
template <typename T> void foo(T*); // overload of foo(T)
template <> void foo<int>(int*); // specialisation of foo(T*)
foo(new int); // calls foo<int>(int*);
Now let's swap the last two.
template <typename T> void foo(T);
template <> void foo<int*>(int*); // specialisation of foo(T)
template <typename T> void foo(T*); // overload of foo(T)
foo(new int); // calls foo(T*) !!!
The compiler does overload resolution before it even looks at specialisations. So, in both cases, overload resolution chooses foo(T*). However, only in the first case does it find foo<int*>(int*) because in the second case the int* specialisation is a specialisation of foo(T), not foo(T*).
You mentioned std::swap. This makes things even more complicated.
The standard says that you can add specialisations to the std namespace. Great, so you have some Foo type and it has a performant swap then you just specialise swap(Foo&, Foo&) in the std namespace. No problems.
But what if Foo is a template class? C++ doesn't have partial specialisation of functions, so you can't specialise swap. Your only choice is overloading, but the standard says that you aren't allowed to add overloads into the std namespace!
You have two options at this point:
Create a swap(Foo<T>&, Foo<T>&) function in your own namespace, and hope that it gets found via ADL. I say "hope" because if the standard library calls swap like std::swap(a, b); then ADL simply won't work.
Ignore the part of the standard that says not to add overloads and do it anyway. Honestly, even though it's technically not allowed, in all realistic scenarios it's going to work.
One thing to remember though is that there's no guarantee that the standard library uses swap at all. Most algorithms use std::iter_swap and in some implementations that I've looked at, it doesn't always forward to std::swap.
There's little to add to Peter Alexander's answer. Let me just mention one use in wich function specialization could be prefearable over overloading: if you have to select among functions with no parameters.
E.g.
template<class T> T zero();
template<> int zero() { return 0; }
template<> long zero() { return 0L; }
To do something similar using function overloading, you would have to add a parameter to the function signature:
int zero(int) { return 0; }
long zero(long) { return 0L; }
You aren't allowed to overload functions in the std namespace, but you are allowed to specialize templates (as I recall), so that's one option.
The other option is to put your swap function in the same namespace as the thing it's operating on and using std::swap; before calling an unqualified swap.

Function template explicit specialization c++

My book mentions two ways for explicit specialization:
template <> void Swap<int> (int &, int &);
template <> void Swap(int &, int&);
what is the difference between both? when to use one and when to use the other? what is exactly the <> after the function name?
what is the difference between both?
There is no difference.
In the second case, you are letting the compiler perform type deduction from the signature of the specialization. Therefore, both forms declare a specialization of Swap<T>() for T = int.
when to use one and when to use the other?
At your discretion, when one form or the other meets your requirements in terms of readability or ease of maintenance.
what is exactly the <> after the function name?
When it comes after the function name, it is the syntax for specifying template arguments:
template<typename T = double, typename U = char>
void foo();
foo<int, bool>(); // Specifies explicit template arguments
foo<>(); // Use default template arguments
foo(); // Same as above, allowed for *function* templates only
When it comes after the template keyword, it is the syntax for introducing a (class or function) template specialization.
The first example is the real way to explicitly specialize a template, the second example is just a shortcut for the first way since the compiler can deduced the type itself from the function signature. The result is the same, there is no real difference.
The <>is used to give the template parameter to a templated structure, in this case the template parameter is the type of the manipulated data and the specialization is for the type int.

Syntax for specializing function templates in C++

Suppose I have a function template where the type parameter is used as a return type only:
template <typename T>
T foo()
{
return whatever;
}
Then what is the correct syntax to specialize that function template? Both of the following seem to work:
template <>
std::string foo()
{
return whatever;
}
template <>
std::string foo<std::string>()
{
return whatever;
}
Is there any difference between the two? If not, what is the idiomatic way?
The compiler will deduce the correct template specialization based on informations provided (here, the function return type).
So these syntaxes have exactly the same behaviour, one being more explicit than the other.
In most case, there is no difference between the two.
If you overload several template functions, the second form may be needed to remove an ambiguity about which overload you mean to specialize (you probably have other problems if you are in this situation, for instance you'll also need to be explicit at call places).

Template Specialization VS Function Overloading

A textbook I have notes that you can provide your own implementation for standard library functions like swap(x,y) via template specialization or function overloading. This would be useful for any types which can benefit from something other than an assignment swap, like STL containers for example (which already have swaps written, I know).
My questions are the following:
What's better: template specialization to give your specialized
swap implementation, or function overloading providing the exact
parameters you wish to use without a template?
Why is it better? Or if they're equal, why is this?
Short story: overload when you can, specialise when you need to.
Long story: C++ treats specialisation and overloads very differently. This is best explained with an example.
template <typename T> void foo(T);
template <typename T> void foo(T*); // overload of foo(T)
template <> void foo<int>(int*); // specialisation of foo(T*)
foo(new int); // calls foo<int>(int*);
Now let's swap the last two.
template <typename T> void foo(T);
template <> void foo<int*>(int*); // specialisation of foo(T)
template <typename T> void foo(T*); // overload of foo(T)
foo(new int); // calls foo(T*) !!!
The compiler does overload resolution before it even looks at specialisations. So, in both cases, overload resolution chooses foo(T*). However, only in the first case does it find foo<int*>(int*) because in the second case the int* specialisation is a specialisation of foo(T), not foo(T*).
You mentioned std::swap. This makes things even more complicated.
The standard says that you can add specialisations to the std namespace. Great, so you have some Foo type and it has a performant swap then you just specialise swap(Foo&, Foo&) in the std namespace. No problems.
But what if Foo is a template class? C++ doesn't have partial specialisation of functions, so you can't specialise swap. Your only choice is overloading, but the standard says that you aren't allowed to add overloads into the std namespace!
You have two options at this point:
Create a swap(Foo<T>&, Foo<T>&) function in your own namespace, and hope that it gets found via ADL. I say "hope" because if the standard library calls swap like std::swap(a, b); then ADL simply won't work.
Ignore the part of the standard that says not to add overloads and do it anyway. Honestly, even though it's technically not allowed, in all realistic scenarios it's going to work.
One thing to remember though is that there's no guarantee that the standard library uses swap at all. Most algorithms use std::iter_swap and in some implementations that I've looked at, it doesn't always forward to std::swap.
There's little to add to Peter Alexander's answer. Let me just mention one use in wich function specialization could be prefearable over overloading: if you have to select among functions with no parameters.
E.g.
template<class T> T zero();
template<> int zero() { return 0; }
template<> long zero() { return 0L; }
To do something similar using function overloading, you would have to add a parameter to the function signature:
int zero(int) { return 0; }
long zero(long) { return 0L; }
You aren't allowed to overload functions in the std namespace, but you are allowed to specialize templates (as I recall), so that's one option.
The other option is to put your swap function in the same namespace as the thing it's operating on and using std::swap; before calling an unqualified swap.

C++ - What is the purpose of function template specialization? When to use it?

Learning C++, came upon function templates. The chapter mentioned template specialization.
template <> void foo<int>(int);
void foo( int );
Why specialize when you can use the second? I thought templates were suppose to generalize. What's the point of specializing a function for a specific data type when you can just use a regular function?
Obviously, template specialization exists for a reason. When should it be used? I read Sutter's "Why not Specialize..." article but I need more of a layman's version since I'm just learning this stuff.
The main difference is that in the first case you are providing the compiler with an implementation for the particular type, while in the second you are providing an unrelated non-templated function.
If you always let the compiler infer the types, non-templated functions will be preferred by the compiler over a template, and the compiler will call the free function instead of the template, so providing a non-templated function that matches the arguments will have the same effect of specializations in most cases.
On the other hand, if at any place you provide the template argument (instead of letting the compiler infer), then it will just call the generic template and probably produce unexpected results:
template <typename T> void f(T) {
std::cout << "generic" << std::endl;
}
void f(int) {
std::cout << "f(int)" << std::endl;
}
int main() {
int x = 0;
double d = 0.0;
f(d); // generic
f(x); // f(int)
f<int>(x); // generic !! maybe not what you want
f<int>(d); // generic (same as above)
}
If you had provided an specialization for int of the template, the last two calls would call that specialization and not the generic template.
I personally can see no benefit from specializing a function template. Overloading it by either a different function template or a non-template function is arguably superior because its handling is more intuitive and it's overall more powerful (effectively by overloading the template, you have a partial specialization of the template, even though technically it's called partial ordering).
Herb Sutter has written an article Why not specialize function templates? where he discourages specializing function templates in favour of either overloading them or writing them so that they just forward to a class template's static function and specializing the class template instead.
You can use specialization when you know for a specific class the generic method could be efficient.
template<typename T>
void MySwap(T& lhs, T& rhs)
{
T tmp(lhs);
lhs = rhs;
rhs = tmp;
}
Now for vectors my swap will work, but is not very effecient. But I also know that std::vector implements its own swap() method.
template<>
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
Please don;t compare to std::swap which is a lot more complex and better written. This is just an example to show that a generic version of MySwap() will work but is may not always be efficient. As a result I have shown how it can be made more efficient with a very specific template specialization.
We can also of course use overloading to achieve the same effect.
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
So the question if why use template specialization (if one can use overloading). Why indeed. A non template function will always be chosen over a template function. So template specialization rules are not even invoked (which makes life a lot simpler as those rules are bizarre if you are not a lawyer as well as a computer programmer). So let me thing a second. No can't think of a good reason.
I find it very important. You can use this as you would use a virtual method. There would be no point in virtual methods unless some of them were specialized. I have used it a lot to differentiate between simple types (int,short,float) and objects, object pointers and object references.
An example would be serialize/unserialize methods that would handle objects by calling the objects serialize/unserialize method, while simple types should be written directly to a stream.
One case for template specialization which is not possible with overloading is for template meta-programming. The following is real code from a library that provides some of it services at compile time.
namespace internal{namespace os{
template <class Os> std::ostream& get();
struct stdout{};
struct stderr{};
template <> inline std::ostream& get<stdout>() { return std::cout; }
template <> inline std::ostream& get<stderr>() { return std::cerr; }
}}
// define a specialization for os::get()
#define DEFINE_FILE(ofs_name,filename)\
namespace internal{namespace os{ \
struct ofs_name{ \
std::ofstream ofs; \
ofs_name(){ ofs.open(filename);} \
~ofs_name(){ ofs.close(); delete this; } \
}; \
template <> inline std::ostream& get<ofs_name>(){ return (new ofs_name())->ofs; } \
}} \
using internal::os::ofs_name;
Multiple overloads on the same name do similar things. Specializations do the exact same thing, but on different types. Overloads have the same name, but may be defined in different scopes. A template is declared in only one scope, and the location of a specialization declaration is insignificant (although it must be at the scope of the enclosing namespace).
For example, if you extend std::swap to support your type, you must do so by specialization, because the function is named std::swap, not simply swap, and the functions in <algorithm> would be quite right to specifically call it as ::std::swap( a, b );. Likewise for any name that might be aliased across namespaces: calling a function may get "harder" once you qualify the name.
The scoping issue is confused further by argument-dependent lookup. Often an overload may be found because it is defined in proximity to the type of one of its arguments. (For example, as a static member function.) This is completely different from how the template specialization would be found, which is by simply looking up the template name, and then looking up the explicit specialization once the template has been chosen as the target of the call.
The rules of ADL are the most confusing part of the standard, so I prefer explicit specialization on the priciple of avoiding reliance on it.