There are, broadly, two categories of template parameters.
template<typename T>
(This is more general than marking parameter T
as a class
or struct
or union
, as it can also include primitive types like int
, bool
, etc.)
Integral constants, i.e. template<int i>
. For instance the following construction is useful in some TMP techniques.
:
template<int k> struct Rank : Rank<k-1> {};
template<> struct Rank<0> {};
This template generates a hierarchy of Rank
types which each inherit from one another, i.e. Rank<0>
is a superclass of Rank<1>
is a superclass of Rank<2>
...
Integral constants can be broadly construed to include char
, and also pointers like int *
or even a pointer to some struct. You can for instance template a class against a pointer to some fixed (static storage duration) instance of a struct of some type in memory somewhere, this can be useful.
You cannot template against anything with a ctor or dtor (when would they run?). You cannot template against a const char *
string literal -- if you attempted to instantiate a type my_type<"foo">
you would never be able to refer to that type again, because when you typed my_type<"foo">
later you would get a different string literal "foo"
and therefore a different pointer and a different type. (You can however template against a particular string with static storage duration.) You also cannot template against float either, because you might expect things like my_type<2.0/3>
and my_type<6.0/9>
to always give you the same type, and then get a rude surprise caused by floating point rounding.
You can also template against function pointers, that's sometimes really useful also.
Pointer-to-member-function templating is also possible, I've used that in the past when making some code that binds C++ classes to lua.
Here's the actual text of C++11 standard (14.1.4)
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
(4.1) — integral or enumeration type,
(4.2) — pointer to object or pointer to function,
(4.3) — lvalue reference to object or lvalue reference to function,
(4.4) — pointer to member,
(4.5) — std::nullptr_t.
[ Note: Other types are disallowed either explicitly below or implicitly by the rules governing the form of
template-arguments (14.3). — end note ] The top-level cv-qualifiers on the template-parameter are ignored
when determining its type.
Actually I didn't know about lvalue reference, I've never actually used that, nor have I used pointer to member besides pointer to member function. I have templated against nullptr
, that is also useful at times.