TEMPLATE PARAMETERS ■ 729 ᮀ Multiple Template Parameters You can also define templates with multiple parameters like the following class template, Example: template <class U, class V> class Demo { // . . . }; which has two parameters U and V. A class Demo<U,V> is defined for each pair of U, V types. A template parameter need not always be a type name. Normal function parameters are also permissible, particularly pointers and references. Example: template<class T, int n> class Stack{ . . . }; This defines the class template Stack<T, n> that is parameterized with the type T and an integer n. The example on the opposite page uses the parameter n to specify the size of an array used to represent a stack. The major advantage is that the number of array elements is already known when an object of the template class is instantiated. Objects can then be created without allocating dynamic storage. This simplifies the definition of the stack template. The copy constructor, the assign- ment operator, and the destructor no longer need to be defined! ᮀ Restrictions Two restrictions apply to template parameters other than type parameters: ■ they cannot be modified ■ they cannot be floating-point types. The following expression would thus be invalid in the definition opposite: Example: ++n; // Error: changing template parameter Even though double type template parameters are not permissible, Example: template<class T, double d> // Error! class Demo { . . . }; pointers and references to floating-point types are: Example: template<class T, double& ref> class Demo { . . . }; 730 ■ CHAPTER 32 TEMPLATES // mini_t.cpp: Passing arguments to // function templates // #include <iostream> using namespace std; template <class T> T min( T x, T y) { return( (x < y) ? x : y); } int main() { short x = 10, y = 2; cout << "x = " << x << " y = " << y << endl; cout << "The smaller value is: " << min(x, y) << endl; // Call is ok. double z1 = 2.2; float z2 = 1.1F; cout << "\nThe smaller value is: " << min(z1, z2) << endl; // Not ok! double z3 = 1.1; cout << "\nz1 = " << z1 << " z3 = " << z3 << endl; cout << "The smaller value is: " << min(z1, z3) << endl; // Call is ok. return 0; } ■ TEMPLATE ARGUMENTS Sample program TEMPLATE ARGUMENTS ■ 731 ᮀ Passing Arguments A template is instantiated when a template argument is passed to it. The argument types must exactly match to the types of the template parameters. Not even implicit type conversions, such as float to double, are performed. In the case of the template function min() this means that both arguments must be of the same type. The following call Example: float x = 1.1; double y = 7.7; min ( x , y ); would lead to an error message, since the template function cannot be defined by the Prototype: void min( float , double ); ᮀ Restrictions There are several restrictions for template arguments other than type names: ■ if the template parameter is a reference, only a global or static object can be passed as a template argument ■ if the template parameter is a pointer, only the address of an object or a function with global scope can be stated ■ if the template parameter is neither a reference nor a pointer, only constant expressions can be used as template arguments. Example: int cnt = 256; // Error: typedef Stack<short, cnt> ShortStack; Since only an int constant is permitted as a template argument, this statement provokes an error. Strings, such as "Oktoberfest," are also invalid as template arguments, as their scope is static and not global. Example: template<class T,char* s> class Demo{ }; Only globally defined strings can be used for instantiation, for example char str[] = "Oktoberfest"; // global Demo<double, str> income; // ok 732 ■ CHAPTER 32 TEMPLATES template <class T> T min( T x, T y) { return( (x < y) ? x : y) } #include <cstring> const char* min( const char* s1, const char* s2 ) { return( (strcmp(s1, s2) < 0 ) ? s1: s2 ); } #include <cstring> template<> const char* min( const char* s1, const char* s2 ) { return( (strcmp(s1, s2) < 0 ) ? s1: s2 ); } ■ SPECIALIZATION Function template min() Specializing the function template for C strings ᮀ ANSI specialization The ANSI standard does not differ between template functions and “normal” functions. The definition of a function template and a function with the same name, which can be generated by the function template, causes the compiler to output an error message (ex. “duplicate definition ”). That is why the ANSI standard provides its own syntax for defining specializations: SPECIALIZATION ■ 733 ᮀ Motivation A template function can only be instantiated if all the statements contained in the func- tion can be executed. If you call the template function exchange() with two objects of the same class, the copy constructor and the assignment must be defined for this class. More specifically, all operators used in a template function must be defined for the current argument type. Thus, the function template min(), which determines the lesser of two arguments, can only be instantiated if the operator < is defined for the argument type. Besides non-executable instructions there are other reasons to prevent a function template being instantiated for a particular type: ■ the generic approach defined by the template does not return any useful results for a given type ■ there are more efficient approaches for some types. The statement Example: minStr = min(, "VIVIAN", "vivian" ); only returns the lower of the two addresses at which the C strings are stored. ᮀ Defining Specialization In cases like this, it makes sense to specialize the template function definition. To do so, you use a function with a separate definition to overload the template function. This technique is demonstrated on the opposite page using the function template min(), where a specialization has been defined for the char* type, both for older and more modern compilers that support the current ANSI standard. If a template function is replaced by a specialization, the appropriate version must be executed when a call to the function is made. The order the compiler looks up a function guarantees that if both a function template and a specialization are defined for a specific type, the specialization will be called. This also applies to the methods of a class template, which are function templates, of course. More specifically, a template class can only be created if all the methods in the appropriate function template can be instantiated without error. 734 ■ CHAPTER 32 TEMPLATES // quadMat.h: Defines the template QuadMatrix // to represent quadratic matrices // #include <iostream> #include <stdexcept> using namespace std; template <class T, int cnt = 10> class QuadMatrix { private: T mat[cnt][cnt]; public: int dim() const{ return cnt; } T* operator[](int line) throw(out_of_range) { if( line < 0 || line >= cnt) throw out_of_range("Matrix: Index out of range"); else return mat[line]; } const T* operator[](int line) const throw(out_of_range) { if( line < 0 || line >= cnt) throw out_of_range("Matrix: Index out of range"); else return mat[line]; } friend QuadMatrix& operator+(const QuadMatrix&, const QuadMatrix&); // etc. }; ■ DEFAULT ARGUMENTS OF TEMPLATES A class template representing quadratic matrices DEFAULT ARGUMENTS OF TEMPLATES ■ 735 ᮀ Setting Defaults You can define default arguments for template parameters, just as for function parame- ters. If an argument required to instantiate a template is missing, the default value is then used. You can specify default values in the template definition or when you declare a tem- plate in a module. ᮀ The Class Template QuadMatrix<T, n> The class template defined opposite, QuadMatrix<T, n>, represents quadratic matri- ces. The subscript operator is overloaded to allow you to access a matrix element m[i][j] in a given matrix m. If the line index i is outside of the valid range, a standard out_of_range type exception is thrown. The default values are chosen to create a matrix m for int values with 10 rows and 10 columns following this definition: Example: typedef QuadMatrix < > IntMat; IntMat m; You cannot omit the angled brackets since the QuadMatrix type does not exist. QuadMatrix is merely the name of a template. The following definition Example: typedef QuadMatrix<double> DoubleMat; DoubleMat dm; defines a matrix dm of double values with 10 rows and 10 columns. ᮀ Rules The same rules apply to the default arguments of templates as to the default arguments of functions: ■ if you declare a default argument for at least one parameter, you must define default values for all the remaining parameters ■ if a template argument for which a default argument was declared is omitted dur- ing instantiation, all the remaining template arguments must be omitted. 736 ■ CHAPTER 32 TEMPLATES // expIns_t.cpp: Tests explicit instantiation // #include <iostream> #include <iomanip> using namespace std; #include "quadMat.h" // Explicit Instantiation: template class QuadMatrix<long double, 5>; int main() { QuadMatrix<long double, 5> m; try { for(int k=0; k < m.dim(); k++) { for( int l = 0; l < m.dim(); l++) { m[k][l] = k*l; cout << setw(2) << m[k][l] << " "; } cout << endl; } } catch(out_of_range& err ) { cerr << err.what() << endl; } return 0; } ■ EXPLICIT INSTANTIATION Sample program for the class template QuadMatrix EXPLICIT INSTANTIATION ■ 737 In addition to implicit instantiation of templates, which occurs when a template func- tion is called, for example, explicit instantiation is also possible. This is important when you design libraries that contain template functions and classes for application programs. ᮀ Syntax Explicit instantiation can be achieved by the following Syntax: template declaration; where declaration contains the name of the template and the template arguments. Explicit instantiation for the class template Stack would be performed as follows: Example: template class Stack<long double, 50>; This declaration creates the template class Stack<long double, 50> with a maxi- mum of 50 long double type elements. Function templates can also be instantiated explicitly. Example: template short min( short x, short y); This creates a template function for the short type from the function template min(). ᮀ ANSI Instantiation The ANSI standard provides an additional technique for the explicit instantiation of function templates. Template arguments are stated in the angled brackets that follow the function name, when the function is first called. Example: min<long>(x, y); In this case, a template function min() for the long type is generated. This advanced syntax for function templates is not supported by all C++ compilers, however. Explicit instantiation of function templates extends their possible usage: ■ function templates can be parameterized by types that cannot be derived from the function arguments—more specifically, function templates can be defined with- out function parameters ■ function templates can be defined with function parameters that are not template parameters themselves. exercises 738 ■ CHAPTER 32 TEMPLATES The left, sorted part originally consists of only one element, the first array element. ✓ NOTE ■ EXERCISES Interpolation search The elements of a numerical array are assumed to be unique and sorted in ascending order. The given value is compared with the array element at the position where the value is “expected” to be. For example, if the value searched for is two-thirds of the way from the lowest to the highest subarray element, the probe would be made two-thirds from the lowest to the highest index of the subarray. If the required value is lesser than that of the array element found at the expected position, the search is continued in the left part of the subarray, just like a binary search. Otherwise the search continues in the right part of the subarray. The “expected” position exp in an array v can be calculated as follows: If key is the required value, begin is the lowest, and end is the highest index of the corresponding subarray, the following applies: double temp = (double)(key-vp[begin]); temp /= (vp[end]-vp[begin]); temp = temp * (end - begin) + 0.5; exp = begin + (int)temp; Insertion sort algorithm The following technique is used to divide the array into a left, sorted part and a right, unsorted part: Each subsequent element in the unsorted part of the array is selected and taken out from the array.As long as a greater array element can be found starting from the end of the left subarray, the element is shifted up by one position. If a smaller array element is found, the selected element is inserted at the vacant position. 30 30 30 50 50 50 70 70 40 70 20 20 20 70 > 40? yes to take out Graphic: ↑ . default argument for at least one parameter, you must define default values for all the remaining parameters ■ if a template argument for which a default argument was declared is omitted dur- ing instantiation,. search is continued in the left part of the subarray, just like a binary search. Otherwise the search continues in the right part of the subarray. The “expected” position exp in an array v can. QuadMatrix&); // etc. }; ■ DEFAULT ARGUMENTS OF TEMPLATES A class template representing quadratic matrices DEFAULT ARGUMENTS OF TEMPLATES ■ 735 ᮀ Setting Defaults You can define default arguments