Indeed the template parameters you defined are non-type parameters, as opposed to the two other varieties of template parameters: type-parameters and template-parameters.
However, they are still template parameters, and you will get an entirely new data type for each distinct set of template arguments. For example, foo<3,'a'>
is a different data type from foo<4,'a'>
, which again is different from foo<3,'b'>
and so forth.
Hence, the static members are separately allocated and initialized for each choice of template arguments, too.
In this respect, non-type parameters, type-parameters and template-parameters all work the same way.
For reference, from the Standard (C++11):
(§14.7/6) Each class template specialization instantiated from a template has its own copy of any static members. [ Example:
template<class T> class X {
static T s;
};
template<class T> T X<T>::s = 0;
X<int> aa;
X<char*> bb;
X<int>
has a static member s
of type int
, and X<char*>
has a static member s
of type char*
. — end example ]
The example given by the Standard above refers to type-parameters, but section 14.7/6 is part of a general discussion of templates. The broader context makes it clear that this holds for templates that use non-type parameters (or a combination of type-, non-type- and template-parameters).
There is also a section on type-equivalence for template instantiations, which explains under what circumstances template instantiations with non-type parameters are considered as equal (relevant parts emphasized by me):
(§14/1) Two template-ids refer to the same class or function if
— their template-names, operator-function-ids, or literal-operator-ids refer to the same template and
— their corresponding type template-arguments are the same type and
— their corresponding non-type template arguments of integral or enumeration type have identical values and
— their corresponding non-type template-arguments of pointer type refer to the same external object or function or are both the null pointer value and
— their corresponding non-type template-arguments of pointer-to-member type refer to the same class member or are both the null member pointer value and
— their corresponding non-type template-arguments of reference type refer to the same external object or function and
— their corresponding template template-arguments refer to the same template.
Put in context, this means that two instantiations of the same class template constitute two distinct data types even if they differ in the value of only a single non-type parameter.