There is the template class List.
template <typename Point>
class List
{
public:
template <const unsigned short N>
void load ( const char *file);
...
};
template <typename Point>
template <const unsigned short N>
void List <Point>::load ( const char *file)
}
How to specialize method load for N=2? This code is not valid...
template <typename Point>
void List <Point> <2>::load ( const char *file)
{
}
And this code also does not work.
template <typename Point>
void List <Point> ::load <2> ( const char *file )
{
}
Error 3 error C2768: 'List<Point>::load' : illegal use of explicit template arguments 66.
Error 5 error C2244: 'List<Point>::load' : unable to match function definition to an existing declaration 66
Compiler g++:
template <typename Point>
template <>
void List <Point> ::load <2> ( const char *file )
{
}
error: explicit specialization in non-namespace scope `class List<>'
error: enclosing class templates are not explicitly specialized
error: default arguments are only permitted for function parameters
error: `load' is not a function template
error: invalid function declaration
It turns out that there's a provision in the C++ spec that explicitly disallows specializing a template class or function nested inside of a template class unless you also explicitly specialize the outer template as well. Visual Studio doesn't enforce this rule, hence the confusion with the previous example, but g++ certainly does.
If you want to specialize the template, your options will either be to also specialize the outer template or to somehow fake up the behavior of specialization by having the method dispatch to one of two different implementations based on the template parameter. Neither of these are very satisfying, I know, but unfortunately the language is designed weirdly in some template corners. :-(
One way that you can emulate the behavior of the explicit specialization is to use a technique called tag dispatching. The idea is that we'll make a very simple struct that looks like this:
This type is completely empty. It's not meant to be used directly, but rather is just a way of embedding an integer into the type system. In particular,
Box<3>
is not the same type asBox<4>
, etc.Next, in your list class, define two functions that look like this, preferably marked private:
These two functions are overloads of one another, distinguishable only by their final parameter, which is either a
Box<N>
in the template case or aBox<2>
in the non-template case. Note that the parameters don't have names. This is an arbitrary decision, but since we're not planning on actually reading the parameters, we don't need them. The intuition behind these functions is that this first function will be the "catch-all" implementation that will work for anyN
except 2. The second version will contain the implementation of loading for the case whereN == 2
.Finally, implement
load
as follows:How does this work? This function takes in a parameter, and then calls
doLoad
forwarding that parameter as the first argument and passing a temporaryBox<N>
as the second argument. IfN
is not two, then this is a call to the template version ofdoLoad
, which is the catch-all handler. If, on the other hand,N
is two, then this will call the non-template version ofdoLoad
, because non-template functions have priority over template functions during overload resolution.In short, the implementation of
load
just becomes a trampoline to forward you to the correct of the two implementations. You can then put the logic in the appropriatedoLoad
function to get the behavior you want.Hope this helps!