GNU Autoconf, Automake, and Libtool

 

Templates--known in other languages as generic types ---permit you to write C++ classes which represent parameterized data types. A common application for class templates is container classes. That is, classes which implement data structures that can contain data of any type. For instance, a well-implemented binary tree is not interested in the type of data in its nodes. Templates have undergone a number of changes since their initial inclusion in the ARM. They are a particularly troublesome C++ language element in that it is difficult to implement templates well in a C++ compiler.

Here is a fictitious and overly simplistic C++ class template that implements a fixed- sized stack. It provides a pair of methods for setting (and getting) the element at the bottom of the stack. It uses the modern C++ template syntax, including the new typename keyword (see section 16.2.8 The typename Keyword).

 

template <typename T> class Stack { public: T first () { return stack[9]; } void set_first (T t) { stack[9] = t; } private: T stack[10]; };

C++ permits this class to be instantiated for any type you like, using calling code that looks something like this:

 

int main () { Stack<int> s; s.set_first (7); cout << s.first () << endl; return 0; }

An old trick for fashioning class templates is to use the C preprocessor. Here is our limited Stack class, rewritten to avoid C++ templates:

 

#define Stack(T) \ class Stack__##T##__LINE__ \ { \ public: \ T first () { return stack[0]; } \ void set_first (T t) { stack[0] = t; } \ \ private: \ T stack[10]; \ }

There is a couple of subtleties being used here that should be highlighted. This generic class declaration uses the C preprocessor operator `##' to generate a type name which is unique amongst stacks of any type. The __LINE__ macro is defined by the preprocessor and is used here to maintain unique names when the template is instantiated multiple times. The trailing semicolon that must follow a class declaration has been omitted from the macro.

 

int main () { Stack (int) s; s.set_first (7); cout << s.first () << endl; return 0; }

The syntax for instantiating a Stack is slightly different to modern C++, but it does work relatively well, since the C++ compiler still applies type checking after the preprocessor has expanded the macro. The main problem is that unless you go to great lengths, the generated type name (such as Stack__int ) could collide with other instances of the same type in the program.

This document was generated by Gary V. Vaughan on May, 24 2001 using texi2html

Категории