Why use template specializations?

176 views Asked by At

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.

4

There are 4 answers

3
David Rodríguez - dribeas On BEST ANSWER

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

2
Sarien On

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. :)

0
Bo Persson On

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.

0
Dirk Holsopple On

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.