I think some of my confusion over what "Specialization" means is that it appears to have two related, though distinct meanings. These are the two definitions I've seem to come across:
From IBM Template Instantiation
The definition created from a template instantiation to handle a specific set of template arguments is called a specialization.
Which seems to mean, if I have some templated class:
template <typename T>
class Foo { ... };
That I create a specialization of Foo
by simply instantiating Foo<int>
for example.
This makes sense, as the template is merely a prototype, from which the compiler is creating a specialized definition specifically for int
.
However, I have also seen template specialization referring to a different concept. Sometimes it seems to be called Full template specialization, while others it seems to be called partial template specialization. This seems to be the act of specifying separate "specialized" code for a subset of template arguments. So say I have this really contrived example where I want getMagnitude()
to return some value for all types except for uint8_t
, for which case I'd want to to first divide the value by 255. I could write this as:
template <typename T>
float getMagnitude(T value)
{
return static_cast<float>(value);
};
template <typename T>
float getMagniude<uint8_t>(T value)
{
return static_cast<float>(value)/255.f;
};
That way I still have a template for getMagnitude()
but I can specialize it to behave differently for different template arguments. This also makes sense why it'd be called specialization, as it is specializing the behavior for certain template arguments.
Online and talking with other people though, it seems like this terminology isn't always clear (at least not to me). Is it the type of thing that should be clear from context alone? Or is there a way of differentiating between these two types of template specialization when speaking/writing documentation? (And further, are there possibly other types of template specialization I'm not aware of?)
The terminology is very clear and precise. Instantiation and specialization are different concepts, and can both be implicit or explicit.
A specialization is a class, variable, function, or class member that is either instantiated ([temp.inst]) from a templated entity or is an explicit specialization ([temp.expl.spec]) of a templated entity.
This is what your quote from the IBM documentation means. Instantiation (explicit or implicit) is one way to produce a specialization. The other way is explicit specialization. Note that an implicit specialization is not to be found in the code. Instead, it is produced at compile-time if necessary (required by an instantiation).
Unless a class template specialization is a declared specialization, the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program.
Instantiation can be implicit (like when using Foo<int>
in your example), which is covered by the quote above, or explicit, which is covered by the quote below.
A class, function, variable, or member template specialization can be explicitly instantiated from its template. A member function, member class or static data member of a class template can be explicitly instantiated from the member definition associated with its class template.
For example:
template <typename T>
class Foo { ... };
template class Foo<int>; // explicit instantiation
Again, this is not an explicit specialization, so the compiler generates the specialization itself. You don't give it any implementation, it comes from the template.
An explicit specialization ([temp.expl.spec]
) is something you write in full. In your (invalid) example with getMagnitude
, it would look like this:
template <typename T>
float getMagnitude(T value)
{
return static_cast<float>(value);
};
template <> // no template parameter
float getMagnitude<uint8_t>(uint8_t value) // explicit types, no `T` anywhere
{
return static_cast<float>(value)/255.f;
};
Here, getMagnitude<uint8_t>
is an explicit specialization of the function template getMagnitude
. You provide the implementation.
This is also known as explicit full template specialization, because all the template parameters are given a type or value. It is no longer a template.
The same can be done with classes. However, you can also partially specialize classes, unlike functions. This is known as class template partial specialization.
A partial specialization of a class template provides an alternative definition of the template that is used instead of the primary definition when the arguments in a specialization match those given in the partial specialization ([temp.class.spec.match]).
Also important:
Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization ([temp.class.spec.mfunc]).
Example:
template <typename T, typename U>
class Foo { ... };
template <typename V>
class Foo<V, V> { ... }; // partial specialization for when T and U are the same
Note that the partial specialization is still a template: it requires at least one template parameter (typename V
in this case, where V
could also be replaced by T
).