I know that the below code is a partial specialization of a class:
template <typename T1, typename T2>
class MyClass {
…
};
// partial specialization: both template parameters have same type
template <typename T>
class MyClass<T,T> {
…
};
Also I know that C++ does not allow function template partial specialization (only full is allowed). But does my code mean that I have partially specialized my function template for one/same type arguments? Because it works for Microsoft Visual Studio 2010 Express! If no, then could you please explain the partial specialization concept?
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
template <typename T1, typename T2>
inline T1 max (T1 const& a, T2 const& b)
{
return a < b ? b : a;
}
template <typename T>
inline T const& max (T const& a, T const& b)
{
return 10;
}
int main ()
{
cout << max(4,4.2) << endl;;
cout << max(5,5) << endl;
int z;
cin>>z;
}
Since partial specialization is not allowed -- as other answers pointed --, you could work around it using
std::is_same
andstd::enable_if
, as below:Output:
Edit: In case you need to be able to treat all the other cases left, you could add a definition which states that already treated cases should not match -- otherwise you'd fall into ambiguous definitions. The definition could be:
Which produces:
Although this all-cases thing looks a bit boring, since you have to tell the compiler everything you've already done, it's quite doable to treat up to 5 or a few more specializations.
If you really want to understand templates, you should take a look at functional languages. The world of templates in C++ is a purely functional sublanguage of its own.
In functional languages, selections are done using Pattern Matching:
As you can see, we overload the definition of
isJust
.Well, C++ class templates work exactly the same way. You provide a main declaration, that states the number and nature of the parameters. It can be just a declaration, or also acts as a definition (your choice), and then you can (if you so wish) provide specializations of the pattern and associate to them a different (otherwise it would be silly) version of the class.
For template functions, specialization is somewhat more awkward: it conflicts somewhat with overload resolution. As such, it has been decided that a specialization would relate to a non-specialized version, and specializations would not be considered during overload resolution. Therefore, the algorithm for selecting the right function becomes:
(for on in-depth treatment, see GotW #49)
As such, template specialization of functions is a second-zone citizen (literally). As far as I am concerned, we would be better off without them: I have yet to encounter a case where a template specialization use could not be solved with overloading instead.
No, it is simply an overload, and this is fine. In fact, overloads usually work as we expect them to, while specializations can be surprising (remember the GotW article I linked).
No. For example, you can legally specialize
std::swap
, but you cannot legally define your own overload. That means that you cannot makestd::swap
work for your own custom class template.Overloading and partial specialization can have the same effect in some cases, but far from all.
Non-class, non-variable partial specialization is not allowed, but as said:
Adding a class to forward the function call can solve this, here is an example:
In the example, you are actually overloading (not specializing) the
max<T1,T2>
function. Partial specialization syntax should have looked somewhat like below (had it been allowed):[Note: in the case of a function template, only full specialization is allowed by the C++ standard (excluding the compiler extensions).]
Late answer, but some late readers might find it useful: Sometimes, a helper function – designed such that it can be specialised – can solve the issue, too.
So let's imagine, this is what we tried to solve:
OK, partial template function specialisation, we cannot do that... So let's "export" the part needed for specialisation into a helper function, specialize that one and use it:
This can be interesting especially if the alternatives (normal overloads instead of specialisations, the workaround proposed by Rubens, ... – not that these are bad or mine is better, just another one) would share quite a lot of common code.