The standard complex template comes ready-made with specializations that use float, double, and long double for the parameter T. The member-template constructor above allows you to create a new complex number that uses a different floating-point type as its base type, as seen in the code below:.
complex
complex
In the declaration of w, the complex template parameter T is double and X is float. Member templates make this kind of flexible conversion easy.
Since defining a template within a template is a nesting operation, the prefixes that introduce the templates must reflect that nesting if you define the member template outside the outer class definition. For example, if you were to implement the complex class template, and if you were to define the member-template constructor above outside the complex template class definition, you would have to do it like this:.
template
template
complex
Another use of member function templates in the standard library is in the initialization of containers, such as a vector. Suppose we have a vector of ints and we want to initialize a new vector of doubles with it, like this:.
int data[5] = {1,2,3,4,5};
vector
vector
As long as the elements in v1 are assignment-compatible with the elements in v2 (as double and int are here), all is well. The vector class template has the following member template constructor:.
template
vector(InputIterator first, InputIterator last,
const Allocator& = Allocator());
This constructor is actually used twice in the vector declarations above. When v1 is initialized from the array of ints, the type InputIterator is int*. When v2 is initialized from v1, an instance of the member template constructor is used with InputIterator representing vector
Member templates can also be classes. (They don’t have to be functions, although that’s usually what you need.) The following example shows a member class template inside an outer class template.
//: C05:MemberClass.cpp
// A member class template
#include
#include
using namespace std;
template
class Outer {
public:
template
class Inner {
public:
void f();
};
};
template
void Outer
cout << "Outer == " << typeid(T).name() << endl;
cout << "Inner == " << typeid(R).name() << endl;
cout << "Full Inner == " << typeid(*this).name() << endl;
}
int main() {
Outer
inner.f();
} ///:~
The typeid operator, which is covered in Chapter 8, returns an object whose name( ) member function yields a string representation of a type or of the type of a variable. Although the exact representation varies from compiler to compiler, the output of the program above should be something like this:.
Outer == int
Inner == bool
Full Inner == Outer
The declaration of the variable inner in the main program instantiates both Inner
Member template functions cannot be declared virtual. Current compiler technology expects to be able to fix the size of a class’s virtual function table when the class is parsed. Allowing virtual member template functions would require knowing all calls to such member functions everywhere in the program ahead of time, which is not feasible, especially for multi-file projects.
Function template issues
Just as a class template describes a family of classes, a function template describes a family of functions. The syntax for creating either type of template is virtually identical, but they differ somewhat in how they are used. You must always use angle brackets when instantiating class templates and you must supply all non-default template arguments. With function templates, on the other hand, you can often omit the template arguments, and default template arguments are not even allowed.[ ]Consider a typical implementation of the min( ) function template declared in the
template
const T& min(const T& a, const T& b) {
return (a < b) ? a : b;
}
You could invoke this template by providing the type of the arguments in angle brackets, just like you do with class templates, as in:
int z = min
This syntax tells the compiler that a specialization of the min template is needed with int used in place of the parameter T, whereupon the compiler generates the corresponding code. Following the pattern of naming the classes generated from class templates, you can think of the name of the instantiated function as min
Type deduction of function template arguments