Let's look at the syntax for template specialization. First, here's a template
template<typename T> void bar() { std::cout << "generic\n"; }
Now, to declare a specialization, you have to provide a different definition for this template, with the template parameters 'filled in' for the template being specialized:
void bar<int>() { std::cout << "special for int\n"; }
except the above isn't legal because a template specialization must also be a template, with it's own parameters that are not the same as those of the template being specialized. In this case we don't have any other parameters so we have to just use an empty template parameter list:
template<>
void bar<int>() { std::cout << "special for int\n"; }
Note that when 'filling in' the template parameters the specific types go in the same place as they do when you use the template, not inside the template<...>
Here's the code from that other question on how to specialize one member of a class template for a specific intantiation of the template.
template <typename T>
struct Node
{
void split() { puts( "Default method" ) ; }
};
template<>
void Node<int>::split() { puts( "Int method" ) ; }
This is the same as
template <typename T>
struct Node
{
void split();
};
// A
template<typename T>
void Node<T>::split() { puts( "Default method" ) ; }
// B
template<>
void Node<int>::split() { puts( "Int method" ) ; }
As you can see, B
is a specialization of A
because the Node<int>
in B
fills in the parameters for A
.
Now look at your code:
template <typename T>
struct Node
{
void split() { puts( "Default method" ) ; }
template <int> void split() { puts( "Int method" ) ; }
};
There's no specialization here. Nothing is 'filling in' template parameters for some other template.
So what does template<int>
mean? At first glance you might think that it means you're 'filling in' some template<typename T>
with T
= int
, but that is not the case. When you fill in template parameters for specializtion, you don't do it inside the template<...>
.
Instead, template<int>
is using something called "non-type template parameters". In template<typename T>
you're creating a template that can be instantiated for different types. E.g.:
template <typename T> void bar();
bar<Foo>();
bar<std::string>();
template<int>
is the same thing, except it lets you get different instantiations for different int
values, rather than different types. See:
template <int N> void baz();
baz<1>();
baz<INT_MAX>();
In the one case the template parameter is a typename
and so the template is instantiated with types. In the other case the template parameter is int
and so the template is instantiated with int
values.
Here's an example of a template that uses non-type template parameters:
template<int N>
struct array{
double arr[N];
};
array<3> k = {{ 0.0, 0.0, 1.0 }}; // has a member 'double arr[3]'
array<2> j = {{ 0.0, 1.0 }}; // has a member 'double arr[2]'
And here's another where the value N
is deduced:
template<typename T,int N>
int size_of_array(T (&my_array)[N]) { // N is deduced from the argument you pass size_of_array
return N;
}
double X[100];
std::cout << size_of_array(X) << '\n'; // instantiates size_of_array<double,100>