Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Mail Systems
Eclipse Documentation

How To Guides
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Problem Solutions
Privacy Policy




Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

Member Templates

The bitset::to_string( ) function template is an example of a member template: a template declared within another class or class template. This allows many combinations of independent template arguments to be combined. A useful example is found in the complex class template in the Standard C++ library. The complex template has a type parameter meant to represent an underlying floating-point type to hold the real and imaginary parts of a complex number. The following code snippet from the standard library shows a member-template constructor in the complex class template:

template<typename T> class complex {
template<class X> complex(const complex<X>&);

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 creates a new complex number that uses a different floating-point type as its base type, as seen in the code below:

complex<float> z(1, 2);
complex<double> w(z);

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.

Defining a template within a template is a nesting operation, so the prefixes that introduce the templates must reflect this nesting if you define the member template outside the outer class definition. For example, if you implement the complex class template, and if you define the member-template constructor outside the complex template class definition, you do it like this:

template<typename T>
template<typename X>
complex<T>::complex(const complex<X>& c) {/* Body here */}

Another use of member function templates in the standard library is in the initialization of containers. 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<int> v1(data, data+5);
vector<double> v2(v1.begin(), v1.end());

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<class InputIterator>
vector(InputIterator first, InputIterator last,
const Allocator& = Allocator());

This constructor is 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<int>::iterator.

Member templates can also be classes. (They don t need to be functions.) The following example shows a member class template inside an outer class template:

//: C05:MemberClass.cpp
// A member class template.
#include <iostream>
#include <typeinfo>
using namespace std;
template<class T> class Outer {
template<class R> class Inner {
void f();
template<class T> template<class R>
void Outer<T>::Inner<R>::f() {
cout << "Outer == " << typeid(T).name() << endl;
cout << "Inner == " << typeid(R).name() << endl;
cout << "Full Inner == " << typeid(*this).name() << endl;
int main() {
Outer<int>::Inner<bool> inner;
} ///:~

The typeid operator, covered in Chapter 8, takes a single argument and returns a type_info object whose name( ) function yields a string representing the argument type. For example, typeid(int).name( ) might return the string int. (The actual string is platform-dependent.) The typeid operator can also take an expression and return a type_info object representing the type of that expression. For example, with int i, typeid(i).name( ) returns something like int, and typeid(&i).name( ) returns something like int *.

The output of the program above should be something like this:

Outer == int
Inner == bool
Full Inner == Outer<int>::Inner<bool>

The declaration of the variable inner in the main program instantiates both Inner<bool> and Outer<int>.

Member template functions cannot be declared virtual. Current compiler technology expects to be able to determine 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. This is not feasible, especially for multi-file projects.

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire