Template non-type arguments (C++ only)

A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be constant expressions, addresses of functions or objects with external linkage, or addresses of static class members. Non-type template arguments are normally used to initialize a class or to specify the sizes of class members.

For non-type integral arguments, the instance argument matches the corresponding template parameter as long as the instance argument has a value and sign appropriate to the parameter type.

For non-type address arguments, the type of the instance argument must be of the form identifier or &identifier, and the type of the instance argument must match the template parameter exactly, except that a function name is changed to a pointer to function type before matching.

The resulting values of non-type template arguments within a template argument list form part of the template class type. If two template class names have the same template name and if their arguments have identical values, they are the same class.

In the following example, a class template is defined that requires a non-type template int argument as well as the type argument:

template<class T, int size> class Myfilebuf
{
      T* filepos;
      static int array[size];
public:
      Myfilebuf() { /* ... */ }
      ~Myfilebuf();
      advance(); // function defined elsewhere in program
};

In this example, the template argument size becomes a part of the template class name. An object of such a template class is created with both the type argument T of the class and the value of the non-type template argument size.

An object x, and its corresponding template class with arguments double and size=200, can be created from this template with a value as its second template argument:

Myfilebuf<double,200> x;

x can also be created using an arithmetic expression:

Myfilebuf<double,10*20> x;

The objects created by these expressions are identical because the template arguments evaluate identically. The value 200 in the first expression could have been represented by an expression whose result at compile time is known to be equal to 200, as shown in the second construction.

Note:
Arguments that contain the < symbol or the > symbol must be enclosed in parentheses to prevent either symbol from being parsed as a template argument list delimiter when it is in fact being used as a relational operator. For example, the arguments in the following definition are valid:
Myfilebuf<double, (75>25)> x;       // valid

The following definition, however, is not valid because the greater than operator (>) is interpreted as the closing delimiter of the template argument list:

Myfilebuf<double, 75>25> x;         // error

If the template arguments do not evaluate identically, the objects created are of different types:

Myfilebuf<double,200> x;            // create object x of class
                                    // Myfilebuf<double,200>
Myfilebuf<double,200.0> y;          // error, 200.0 is a double,
                                    // not an int

The instantiation of y fails because the value 200.0 is of type double, and the template argument is of type int.

The following two objects:

      Myfilebuf<double, 128> x
      Myfilebuf<double, 512> y

are objects of separate template specializations. Referring either of these objects later with Myfilebuf<double> is an error.

A class template does not need to have a type argument if it has non-type arguments. For example, the following template is a valid class template:

template<int i> class C
{
      public:
            int k;
            C() { k = i; }
};

This class template can be instantiated by declarations such as:

class C<100>;
class C<200>;

Again, these two declarations refer to distinct classes because the values of their non-type arguments differ.

Related information