home *** CD-ROM | disk | FTP | other *** search
- .nr PS 10
- .nr VS 12
- .nr PD .7v
- .nr LL 6.5i
- .TL
- A Portable Implementation of Parameterized Templates
- Using A Sophisticated C++ Macro Facility
- .AU
- Mary Fontana
- LaMott Oren
- .AI
- Texas Instruments Incorporated
- Computer Science Center
- Dallas, Texas, 75265
- .AU
- Martin Neath
- .AI
- Texas Instruments Incorporated
- Information Technology Group
- Austin, Texas, 78759
- .AB
- The Texas Instruments C++ Object-Oriented Library (COOL) is a collection of
- classes, templates and macros for use by C++ programmers writing complex
- applications. Parameterized types, symbolic computing and exception handling
- are significant features of COOL which improve the development capabilities
- available to the programmer. These features are implemented in COOL with a
- sophisticated C++ macro facility. This paper describes the COOL macro
- facility, discusses how support for parameterized templates is built upon it,
- and provides details of two programmer interfaces (both implemented) for easy
- use of parameterized templates in application programs.
- .AE
- .NH 1
- Introduction
- .LP
- The Texas Instruments C++ Object-Oriented Library (COOL) is a
- system-independent software platform consisting of classes, templates and
- macros for use by C++ programmers writing complex applications. It is designed
- to raise the level of abstraction for the programmer in order to facilitate
- concentration on the problem domain, not on implementing basic data structures,
- macros, and classes. Parameterized templates, symbolic computing, and
- exception handling are significant features of COOL that substantially improve
- the development capabilities available. We wished to provide these facilities
- in a compiler- and machine-independent manner across several hardware
- platforms. We examined the macro language found in standard C-preprocessors
- and determined that it was insufficient for implementing these features. As a
- result, we developed the COOL macro facility to allow the programmer to define
- powerful extensions to the C++ language in a seamless and unobtrusive manner.
- This macro facility is implemented as an extension to a C preprocessor [1].
- The modifications made to the preprocessor are both portable and compiler
- independent. This paper describes this enhanced macro facility, discusses how
- parameterized templates is built upon it, and provides details of two
- programmer interfaces (both implemented) for easy use of parameterized
- templates. For an overview of COOL see the paper,
- .I
- COOL - A C++ Object-Oriented Library
- .R
- [2].
- For complete details, see the reference document,
- .I
- COOL User's Manual
- .R
- [3].
- .FS
- The authors may be reached via electronic mail at fontana@csc.ti.com,
- oren@csc.ti.com, and neath@itg.ti.com.
- .FE
- .NH 1
- The COOL Preprocessor and the defmacro Keyword
- .LP
- Many C++ language implementations separate the preprocessor and compiler
- functions into two separate programs. Others combine the preprocessor and
- compiler into one step. Since we needed a portable utility to massage C++
- source code that works under both scenarios and executes after include files
- and standard preprocessor directives have been expanded, but before the C++
- compiler itself begins parsing, we decided to modify a C-preprocessor to
- support the COOL C++ language extensions. Thus, the COOL preprocessor is
- derived from and based upon a public domain C-preprocessor (the DECUS C
- preprocessor) made available by the DEC User's group and supplied on the X11R3
- source tape from MIT. It has been modified to comply with the draft ANSI C
- specification with the exception that trigraph sequences are not supported.
-
- The draft-proposed ANSI C standard indicates that extensions and changes to the
- language or features implemented in a preprocessor or compiler should be made
- by using the \fB#pragma\fR keyword. The COOL preprocessor recognizes a
- \fB#pragma defmacro\fR declaration and is the single hook through which
- features such as the class macro, parameterized templates, and polymorphic
- enhancements have been implemented. The \fBdefmacro\fR keyword provides a way
- to define and execute arbitrary filter programs or macro expanders on C++ code
- fragments. The syntax of the \fBdefmacro\fR declaration is:
- .DS I
- \fB#pragma \fBdefmacro \fIname \fB"\fIprogram\fB"\fI options\fR
- \fB#pragma \fBdefmacro \fIname \fB<\fIprogram\fB>\fI options\fR
- .DE
- where \fIname\fR is the name of the macro, \fIprogram\fR is either the name of
- an executable file or the name of an internal preprocessor function which
- implements the macro expansion, and \fIoptions\fR are any combination of the
- following optional parameters:
- .DS I
- \fBrecursive\fR - the macro may be recursively expanded.
- \fBexpanding\fR - the input to the macro is expanded.
- \fBdelimiter= \fIx\fR - the default delimiter (semi-colon) is replaced with \fIx\fR.
- .DE
- Unknown \fIoptions\fR are passed as arguments to the macro expander named
- \fIprogram\fR. This provides the necessary handle through which COOL functions
- and language extensions can be identified. For example, the \fBMACRO\fR
- and \fBtemplate\fR keywords are defined in a top-level header file with:
- .DS I
- #pragma defmacro MACRO "macro" delimiter=} recursive
- #pragma defmacro template "template" delimiter=}
- .DE
- The implementation of the macro expander program may be either external or
- internal to the preprocessor. Fundamental COOL macro-expanders are implemented
- internal to the COOL preprocessor for the sole reason of providing a more
- efficient execution profile to reduce compile time for the application
- programmer. When the preprocessor encounters a \fBdefmacro\fR declaration in
- the source code, it searches first for an executable file named \fIprogram\fR
- on the same search path as that used for include files. If a match is not
- found, it then searches for \fIprogram\fR in an internal preprocessor function
- table. If a match is still not found, an error is reported indicating that the
- macro expander could not be found. This search order allows an internal
- preprocessor definition to be overridden by an external one.
-
- When a \fBdefmacro\fR name is successfully recognized, the name and all
- following characters upto and including the delimiter character (including all
- matching and nested levels of \fB{} [] () <> "" ''\fR and comments found along
- the way) are piped into the standard input of the macro expander program. The
- expander program performs whatever function(s) is appropriate and the resulting
- massaged character stream is piped back onto the standard output of the macro
- expander. This output stream is scanned as new input by the preprocessor for
- any further processing that might be necessary. The original text in the source
- file is replaced with the preprocessor output before being sent onto the C++
- compiler. The expansion replacing a \fBdefmacro\fR name in the source code is
- C++ 2.0 syntax acceptable to any conforming C++ translator or compiler [4].
- .NH 1
- The MACRO Keyword
- .LP
- The COOL \fBMACRO\fR keyword provides a powerful and flexible macro
- capability used to implement and simplify many of the features and functions
- contained in the library. A \fBdefmacro\fR named \fBMACRO\fR (all uppercase)
- provides an enhanced \fB#define\fR macro that supports multi-line, arbitrary
- length, nested macros and cpp-directives with positional, optional, optional
- keyword, required keyword, rest, and body arguments. \fBMACRO\fR has the
- following syntax:
- .DS I
- \fBMACRO \fIname\fR \fB( \fIparmlist\fR\fB ) { \fIbody\fR \fB}\fR
- \fIparmlist\fR := [\fBKEY:\fR | \fBREST:\fR | \fBBODY:\fR] \fIidentifier\fR [\fB=\fR \fIidentifier\fR] [\fB,\fR \fIparmlist\fR]
- .DE
- where \fIname\fR is the name of the macro, \fIparmlist\fR is a list of
- parameters separated by commas, and \fIbody\fR is the code which replaces the
- \fBMACRO\fR reference. The \fIparmlist\fR specification allows positional,
- keyword, rest, and body parameters to be identified by the programmer. The
- positional and keyword parameters may be required or optional. Optional
- parameters are supported by use of an equal sign followed by an
- \fIidentifier\fR that specifies the default value. All the optional
- positional parameters must follow all of the required positional ones.
-
- When \fBKEY:\fR is specified in the \fIparmlist\fR, all parameters which follow
- are keyword parameters. Keyword parameters are position-independent
- parameters. A keyword parameter is provided a value in an argument list by
- supplying the keyword name followed by an equal sign and the argument value.
- \fBREST:\fR in the \fIparmlist\fR indicates that the remaining parameters are
- referenced by one named \fIidentifier\fR. An optional equal sign followed by
- an \fIidentifier\fR sets the \fIidentifier\fR after the equal sign to the
- number of arguments remaining. Finally, \fBBODY:\fR in the \fIparmlist\fR
- indicates that the parameter which follows is expanded to include all the
- source code within the braces after the \fBMACRO\fR call. This is useful for
- passing a source code fragment onto other nested \fBMACRO\fRs. Examples of these
- three types of arguments are given below.
- .NH 2
- MACRO Examples
- .LP
- The following examples show some of the power and flexibility of \fBMACRO\fR.
- This first example uses both positional parameters and keyword parameters.
- .DS I
- MACRO set_val (size, value=NULL, KEY: low=0, high) {
- init (size, value, low, (high-low))
- }
- .DE
- \fBset_val\fR has three parameters: \fIsize\fR is a required positional
- parameter, \fIvalue\fR is an optional positional parameter that if not
- specified in a particular call has a default value of \fBNULL\fR, \fIlow\fR is
- an optional keyword parameter with a default value of \fB0\fR, and \fIhigh\fR is
- a required keyword parameter. In this example, the expansion calls the
- function \fBinit\fR with four arguments. The following shows several expansions
- of \fBset_val\fR.
- .DS I
- set_val (0, high=20) ----> init (0, NULL, 0, (20-0))
- set_val (0, low=5, high=15) ----> init (0, NULL, 5, (15-5))
- set_val (1, 2, high=25) ----> init (1, 2, 0, (25-0))
- .DE
- The next example uses the \fBREST:\fR parameter. Note that there are two
- \fBMACRO\fRs defined: \fBbuild_table\fR calls \fBbuild_table_internal\fR
- to do most of the work.
- .DS I
- MACRO build_table (name, REST: rest) {
- char* name[] = { build_table_internal(rest) NULL}
- }
-
- MACRO build_table_internal (first, REST: rest=count) {
- #first,
- #if count
- build_table_internal (rest)
- #endif
- }
- .DE
- \fBbuild_table\fR has two parameters: \fIname\fR is the name of the table of
- \fBchar*\fR's and \fIrest\fR refers to all the remaining arguments.
- \fBbuild_table\fR calls \fBbuild_table_internal\fR passing its \fIrest\fR
- argument. Note that this call is embedded within the initialization braces of
- the table and is followed by a \fBNULL\fR. In \fBbuild_table_internal\fR,
- \fIfirst\fR is set to the first argument of the \fIrest\fR argument list in the
- invoking macro call, and the remaining \fIcount\fR arguments are left in
- \fIrest\fR. \fBbuild_table_internal\fR uses the ANSI \fB#\fR character on
- \fIfirst\fR to double quote the value. A conditional clause tests \fIcount\fR
- to see if there are remaining arguments. If \fIcount\fR is non-zero, the macro
- is called recursively with the remaining arguments. When there are no more
- arguments, \fBbuild_table\fR regains control and appends the \fBNULL\fR
- character and closing brace to the result of \fBbuild_table_internal\fR.
-
- A sample use of \fBbuild_table\fR is shown below to illustrate the construction
- of a \fBNULL\fR-terminated table containing character strings. The first line
- shows the macro call and the second shows the resulting expansion.
- .DS I
- build_table (table, 1,2,3,4,5,6,7);
- .DE
- expands to:
- .DS I
- char* table[] = {"1", "2", "3", "4", "5", "6", "7", NULL};
- .DE
- This last example uses the \fBBODY:\fR parameter and also takes advantage of
- the current position feature found in the COOL container classes [2]. This is
- used to implement a general purpose loop macro similar to that found in Common
- LISP [5].
- .DS I
- MACRO LOOP (type, identifier, object, BODY: body) {
- { type identifier;
- for ( object.reset(); object.next(); ) {
- identifier = object.value();
- body
- }
- }
- }
- .DE
- \fBLOOP\fR has four parameters: \fItype\fR is the type of each element in a
- container class (such as, \fBint\fR), \fIidentifier\fR is the name of a
- variable to be declared of the given type, \fIobject\fR is the name of a
- container class instance, and \fIbody\fR is the body of code to apply on each
- element in the container object. A specific example for the parameterized
- \fBList<int>\fR class is shown below.
- .DS I
- extern List<int> list1;
- LOOP (int, var1, list1) { cout << var1; }
- .DE
- expands to:
- .DS I
- extern List<int> list1;
- { int var1;
- for ( list1.reset(); list1.next(); ) {
- var1 = list1.value();
- cout << var1;
- }
- }
- .DE
- In this example, \fBlist1\fR is an instance of \fBList<int>\fR which is a
- container class representing a list of integers. \fBLOOP\fR takes this list
- object and iterates through the elements, assigning each to a temporary integer
- variable \fBvar1\fR and printing its value. The net result will print all
- elements in the list.
- .NH 1
- COOL Parameterized Templates
- .LP
- One of the main uses of the COOL macro facility is the implementation
- of \fBtemplate\fR, \fBDECLARE\fR and \fBIMPLEMENT\fR for supporting
- parameterized templates. The syntax of the \fBtemplate\fR grammar is that as
- specified by Stroustrup in his paper,
- .I
- Parameterized Types for C++
- .R
- [6].
- COOL fully implements this functionality such that there will be minimal source
- code conversion necessary when this feature is finally implemented in the C++
- language. COOL provides templates for a number of parameterized classes (such
- as, \fBRange\fR and \fBIterator\fR) and container classes (such as,
- \fBVector\fR, \fB List\fR, \fBBinary_Tree\fR and \fBHash_Table\fR) which are
- described in
- .I
- COOL User's Guide
- .R
- [3].
- .NH 2
- The template Keyword
- .LP
- The \fBtemplate\fR keyword provides a mechanism for defining parameterized
- classes. A parameterized class is a type-independent class. A typical use is
- a container class where the type of the contained object is specified at
- compile-time. For example, vectors can be declared to hold a specific type
- of element, such as, a vector of integers or a vector of doubles,
- from a single parameterized class, \fBVector<\fItype\fB>\fR.
-
- A \fBtemplate\fR is divided into the declarative part and the implementation
- part of a class. The declarative part may occur many times in an application
- and is analogous to including a header file for a class which contains the
- class definition and its inline member functions. The implementation part is
- analogous to the file that contains the source code implementing the member and
- friend functions of the class. COOL provides four variations of \fBtemplate\fR
- for these two parts:
-
- .DS I
- \fBtemplate\fR <\fBclass\fR \fItype\fR [, \fIparms\fR]> \fBclass\fR \fIname\fR<\fItype\fR> { \fIclass_description\fR };
- .RS
- Defines the class template for the declarative part of the \fIname\fR class.
- .RE
-
- \fBtemplate\fR <\fBclass\fR \fItype\fR [, \fIparms\fR]> \fBinline\fR \fIresult name\fR<\fItype\fR>::\fIfunction\fR { ... };
- .RS
- Defines an inline member function for the declarative part of the \fIname\fR
- class.
- .RE
-
- \fBtemplate\fR <\fBclass\fR \fItype\fR [, \fIparms\fR]> \fIresult\fR \fIname\fR<\fItype\fR>::\fIfunction\fR { ... };
- .RS
- Defines a member function for the implementation part of the \fIname\fR class.
- .RE
-
- \fBtemplate\fR <\fBclass\fR \fItype\fR [, \fIparms\fR]> \fIname\fR { \fIanything\fR };
- .RS
- Defines anything else associated with a template for the \fIname\fR class.
- .RE
- .DE
- This last form is used to define such things as \fBtypedef\fRs or friend
- functions of a parameterized class. When this form is found before the class
- template, the contents are expanded before the class definition. When this
- form is found after the class template, the contents are expanded as part of
- the class implementation. Note that this form is not part of the parameterized
- type syntax described by Stroustrup [6]. Rather, it is something we found
- lacking in the original proposal and found very useful in several COOL
- container classes for defining predicate types for the class under C++ 2.0.
- Another use of this form is to provide automatic declarations of nested
- parameterized classes, that is, to declare a parameterized class for a class
- template which is itself derived from another parameterized class template.
-
- Each variation of \fBtemplate\fR allows additional optional parameters
- with the following syntax:
- .DS I
- \fIparms\fR ::= \fItype name\fR [\fB=\fR \fIvalue\fR] [\fB,\fR \fIparms\fR]
- .DE
- where \fItype\fR is the type of the parameter, (such as, \fBclass\fR or
- \fBint\fR); \fIname\fR is the name of the parameter that is substituted when
- \fBtemplate\fR is expanded; and \fIvalue\fR is the default value of parameter
- \fIname\fR.
-
- The following is an example of \fBtemplate\fR for the class,
- \fBVector<\fItype\fB>\fB.
- .DS I
- template <class Type> Vector { // predicate functions
- typedef int (*Vector_##Type##_Predicate) (const Type&, const Type&);
- typedef Boolean (*Vector_##Type##_Compare) (const Type&, const Type&);
- };
- .DE
- .DS I
- template <class Type> class Vector<Type> { // Parameterized Vector class
- private:
- Type* v; // Vector of pointer to Type
- int num_elements; // Element count
- int size; // Size of vector object
- public:
- Vector<Type> (); // Empty constructor
- Vector<Type> (int); // Constructor with size
- Vector<Type> (const Vector<Type>&); // Constructor with reference
- ~Vector<Type> (); // Destructor
- inline Type& operator[](int n); // Operator[] overload for Type
- .DE
- .DS I
- ... // ... other member functions ...
- };
- .DE
- .DS I
- template <class Type> // Overload operator []
- inline Type& Vector<Type>::operator[] (int n) {
- return this->v[n];
- }
- .DE
- .DS I
- template <class Type> // Constructor with size
- Vector<Type>::Vector<Type> (int n) {
- this->v = new Type[n];
- this->size = n;
- this->num_elements = 0;
- }
-
- ... // ... other member functions ...
- .DE
- .NH 2
- An Initial Programmer Interface: DECLARE and IMPLEMENT
- .LP
- As stated earlier, a \fBtemplate\fR for a parameterized class is divided into a
- declarative part and an implementation part. In our first attempt at
- implementing parameterized template support, the programmer creates instances
- of a parameterized class using \fBDECLARE\fR to expand the declarative part and
- \fBIMPLEMENT\fR to expand the implementation part. \fBDECLARE\fR defines the
- parameterized class for a specific type and \fBIMPLEMENT\fR generates the
- member functions supporting this type-specific class. \fBDECLARE\fR must be
- used in every file that includes or makes use of the parameterized class.
- \fBIMPLEMENT\fR must be used only once in the application for each type over
- which the class is parameterized; otherwise the linker will generate errors
- about multiple versions of the same member functions. For example, to create a
- vector of doubles, the following would be used:
- .DS I
- #include <Vector.h>
- DECLARE Vector<double>;
- IMPLEMENT Vector<double>;
- Vector<double> vs(30);
- .DE
- \fBDECLARE\fR expands to code which defines a vector class of doubles and its
- associated inline member functions. \fBIMPLEMENT\fR causes a class definition
- with its associated member functions to be generated and expanded in the file.
- When compiled, this causes the class \fBVector_double\fR to be declared and
- defined. One drawback of the use of \fBIMPLEMENT\fR, however, is the fact that
- the \fIentire\fR class with all its member functions is generated and linked
- into the program image, even if the programmer only requires the use of two or
- three member functions. This problem can be avoided by the use of the COOL C++
- Control Program (\fBCCC\fR) discussed below. Continuing with the example above,
- the \fBtemplate\fR for the \fBVector<\fItype\fB>\fR class for doubles would
- expand to the following code:
- .DS I
- // predicate functions
- typedef int (*Vector_double_Predicate) (const double&, const double&);
- typedef Boolean (*Vector_double_Compare) (const double&, const double&);
- .DE
- .DS I
- class Vector_double { // Parameterized Vector class
- private:
- double* v; // Vector of pointer to double
- int num_elements; // Element count
- int size; // Size of vector object
- public:
- Vector_double (); // Empty constructor
- Vector_double (int); // Constructor with size
- Vector_double (const Vector_double&); // Constructor with reference
- ~Vector_double (); // Destructor
- inline double& operator[](int n); // Operator[] overload for double
- .DE
- .DS I
- ... // ... other member functions ...
- };
- .DE
- .DS I
- // Overload operator []
- inline double& Vector_double::operator[] (int n) {
- return this->v[n];
- }
- .DE
- .DS I
- // Constructor with size
- Vector_double::Vector_double (int n) {
- this->v = new double[n];
- this->size = n;
- this->num_elements = 0;
- }
-
- ... // ... other member functions ...
-
- Vector_double vs(30);
- .DE
- Declarations of nested parameterized types and the use of non-type arguments in
- a template definition are also supported. For example, it is possible to
- declare a vector of vectors of ints with \fBVector<Vector<int>>\fR. In
- addition, a class template derived from another class template is supported,
- that is, a type parameter in one template class can be used to declare another
- class template of that type. For example, the COOL
- \fBAssociation<\fIT1\fR,\fIT2\fB>\fR class is
- a parameterized container class that takes two type arguments, \fIT1\fR and
- \fIT2\fR. The header file for this class has the following templates.
- .DS I
- template <class T1, T2> Association {
- DECLARE Pair<T1, T2>; // Declare Pair object type
- DECLARE Vector<Pair<T1, T2>>; // Declare Vector of Pairs
- }
-
- ... // ...
- // Association<T1,T2> class definition here
-
- .DE
- .DS I
- template <class T1, T2> Association {
- IMPLEMENT Pair<T1, T2>;
- IMPLEMENT Vector<Pair<T1, T2>>;
- }
- .DE
- By using \fBtemplate\fR in this manner, \fBDECLARE\fR for the
- \fBAssociation<\fIT1\fR,\fIT2\fB>\fR class invokes \fBDECLARE\fR on the correct
- types for the \fBPair<\fIT1\fR,\fIT2\fB>\fR and \fBVector<\fIType\fB>\fR
- classes. Likewise, \fBIMPLEMENT\fR for the
- \fBAssociation<\fIT1\fR,\fIT2\fB>\fR class invokes \fBIMPLEMENT\fR for the
- \fBPair<\fIT1\fR,\fIT2\fB>\fR and \fBVector<\fIType\fB>\fR classes.
-
- Non-type arguments as template parameters are used to provide guidelines to be
- used when a template is expanded. For example, the
- \fBN_Tree<\fINode\fR,\fIType\fR,\fInchild\fB>\fR class in COOL takes as
- arguments a node type (either static or dynamic), a type specifying the
- value-type each node will hold, and an argument that specifies the number of
- initial subtrees (or children) each node is to have. The node argument is
- itself the name of a parameterized class and a nested parameterized template
- definition is automatically generated based upon the supplied type and number
- arguments. As such, a single template can be used to generate several different
- classes with different behaviors and features.
- .NH 2
- A Revised Programmer Interface: COOL C++ Control Program (CCC)
- .LP
- The \fBDECLARE\fR and \fBIMPLEMENT\fR macros discussed above were the first
- programmer interface implemented for parameterized template support. We soon
- discovered, however, that this macro expansion mechanism had two serious
- problems. First, the type over which a class was parameterized would have to
- support all operators used in the template, even if not applicable or needed.
- For example, the COOL \fBList<\fIType\fB>\fR class has several member functions
- that use \fBoperator<\fR. However, if what the programmer needs is a list of
- window objects and does not ever use \fBList<\fIType\fB>\fR member functions
- that require \fBoperator<\fR, compile-time errors from the offending functions
- that got macro-expanded are nevertheless generated. Second, with the simplistic
- linkers available on many operating systems today, an application gets all of
- these member functions linked into the executable image. Typically, an
- application uses only a small percentage of the member functions of a
- parameterized class. The remaining unused member functions are useless
- overhead, increasing program size and memory requirements.
-
- A revised programmer interface for parameterized templates was implemented to
- resolve these problems and centers around a new program to be used as the main
- interface between the user and the preprocessor/compiler in a make file. This
- program, the COOL C++ Control program (\fBCCC\fR), augments the standard
- \fBCC\fR script. For most operations, user options and command line arguments
- are passed straight through to the underlying CC program. However, when the
- \fB-X\fR option is specified, the \fBCCC\fR program goes to work in the
- following manner. As Stroustrup[6] suggested, \fB-X"Foo<Bar>"\fR is used on
- the command line to indicate that the programmer wants to parameterize class
- \fBFoo<\fIType\fB>\fR over some type \fBBar\fR. Additional options for include
- file search path and a user-defined library archive are required as described
- below. \fBCCC\fR finds the header file(s) implementing class Foo and type Bar,
- then proceeds to define that type for the compiler. It then \fIfractures\fR
- the implementation of this new type along template boundaries, placing each
- non-inline member function in a separate source file, compiling it, and putting
- the resulting object file in a user-specified library archive. If a particular
- operator is not defined for the type over which the class is parameterized (as
- with the example of \fBoperator<\fR above), a compile time error for that one
- file is generated. However, the remaining member functions, one in each
- fractured template, are still compiled and added to the user library.
-
- For each parameterized class in an application, \fBCCC\fR fractures the
- parameterized class definition along template boundaries, causing each
- \fBtemplate\fR specifying a member function of the parameterized class to be
- compiled into a separate object file. These separate object files are then
- added to an application-specific object library. Since each member function is
- in its own object module in the library, only those member functions actually
- used in the application are linked into the final executable image. To use
- \fBCCC\fR, the programmer specifies a library name, one or more header files
- containing templates, and specific parameterized classes as command line
- arguments to \fBCCC\fR. Other arguments are passed on unchanged to the C++
- compiler and system linker. A single invocation of \fBCCC\fR can either
- process a parameterized class type or compile a C++ source file, but not both.
- For example,
- .DS I
- CCC -lapp -c List.h String.h -X "List<String>"
- .DE
- expands the template for a list of strings. The resulting object files from
- the fractured parameterized \fBList<\fIType\fB>\fR class are stored in
- the library, \fBlibapp.a\fR. The \fB-c\fR option is passed to the compiler to
- indicate that it should not continue with the link phase. The library archive
- \fBlibapp.a\fR is added to the list of libraries specified in the make file
- to be searched during the link step.
-
- The net result is a library archive containing object files, each implementing
- one member function for the parameterized class and type. This process solves
- the two problems identified above with the use of the macros \fBDECLARE\fR and
- \fBIMPLEMENT\fR. First, operators not defined for a type cause compile-time
- errors on that one file. Once a parameterized class has been implemented and
- provided in a library, compile errors will only occur when a type is selected
- that does not have all operators implemented. The user of the class will see
- these, and if the member function in question is required, s/he can add that
- necessary operator to the type class. Second, only member functions actually
- used in an application are linked into the final executable image.
- .NH 2
- Future Improvements to CCC
- .LP
- \fBCCC\fR essentially provides a more sophisticated version of the
- \fBIMPLEMENT\fR macro discussed above. However, the programmer is still
- required to place the \fBDECLARE\fR macro in the appropriate files. One
- option under consideration to resolve this problem is the use of a command line
- switch similar to the +e0/+e1 switchs on the AT&T cfront translator. Under this
- scenario, the equivalent of the +e0 option would be used to declare the type for
- a parameterized class and generate the inline member functions (as the
- \fBDECLARE\fR macro does) but not to generate the remaining member functions.
- The programmer would use the equivalent of the +e1 option on one source file to
- cause the remaining non-inline member functions to be generated and placed in a
- library archive.
-
- A second problem with \fBCCC\fR concerns the specification of nested
- parameterized classes. A programmer should be able to use
- \fB-X"Vector<List<int>>"\fR on the command line to specify creation of nested
- parameterized classes. Currently, \fBCCC\fR does not handle this case
- appropriately. A more sophisticated command line parser should be able to
- recognize and implement nested types before trying to expand the outer most
- parameterized class.
- .NH 1
- Conclusion
- .LP
- The COOL macro facility provides a mechanism to implement significant language
- features and extensions for C++ that are unavailable with current language
- implementations. The macro facility is implemented in an enhanced preprocessor
- that is both efficient and portable, thus allowing for delivery of enhanced
- language features on many platforms. This macro extension is at the heart of
- the parameterized templates functionality. \fBCCC\fR is used in place of the
- normal procedure for controlling the compilation process. It provides all of
- the functionality of the original \fBCC\fR program with additional support for
- the COOL preprocessor and parameterized type expansion. Finally, the
- preprocessor provides an ideal mechanism for quickly prototyping and testing
- additional language functions and syntax without requiring access to or
- modification of a compiler.
- .NH 1
- Status of COOL
- .LP
- Texas Instruments has been using the enhanced macro facility and the
- implementation of parameterized templates internally on several projects for
- the last year. Many classes and programs have been successfully designed and
- implemented, taking full advantage of the power of parameterized templates and
- the enhanced macro facility. In particular, we have found that the use of a
- class library supplying many basic parameterized container classes
- significantly increases the productivity of the programmer, enabling
- applications to be prototyped in a shorter time period than might otherwise be
- possible. COOL is currently up and running on a Sun SPARCstation 1 (TM)
- running SunOS (TM) 4.x,
- .FS
- SunOS and SPARCstation 1 are trademarks of Sun Microsystems, Inc.
- .FE
- a PS/2 (TM)
- .FS
- PS/2 is a trademark of International Business Machines Corporation.
- .FE
- model 70 running SCO XENIX\(rg
- .FS
- XENIX is a registered trademark of Microsoft Corporation.
- .FE
- 2.3, a PS/2 model 70 running OS/2 1.2, and a MIPS running RISC/os 4.0. The
- SPARC and MIPS ports utilize the AT&T C++ translator (cfront) version 2.1 and
- the XENIX and OS/2 ports utilize the Glockenspiel translator 2.0a with the
- Microsoft C 6.0 compiler.
-
- The COOL preprocessor source code is available in compressed tar(1) format in
- the file /pub/cpp.tar.Z via anonymous FTP from CSC.TI.COM (128.247.159.141).
- Permission is granted to any individual or institution to use, copy, modify,
- and distribute this software, provided that all copyright statements and
- permission notices are maintained, intact, in all copies and supporting
- documentation. Texas Instruments Incorporated provides this software "as is"
- without express or implied warranty.
- .NH 1
- References
- .IP [1]
- Brian Kernighan and Dennis Richie,
- .I
- The C Programming Language,
- .R
- Second Edition, Printice-Hill, Englewood Cliffs, NJ, 1988.
- .IP [2]
- Mary Fontana, Martin Neath and Lamott Oren,
- .I
- COOL - A C++ Object-Oriented Library,
- .R
- Information Technology Group, Austin, TX, TI Internal Document, Original Issue January 1990.
- .IP [3]
- Texas Instruments Incorporated,
- .I
- C++ Object-Oriented Library User's Manual,
- .R
- Information Technology Group, Austin, TX, TI Internal Document, Original Issue January 1990.
- .IP [4]
- AT&T Incorporated,
- .I
- C++ Language System Release 2.0,
- .R
- AT&T Product Reference Manual Select Code 307-146, 1989.
- .IP [5]
- Guy L. Steele Jr,
- .I
- Common LISP: The Language,
- .R
- Second Edition, 1990.
- .IP [6]
- Bjarne Stroustrup,
- .I
- Parameterized Types for C++,
- .R
- Proceedings of the USENIX C++ Conference, Denver, CO, October 17-21, 1988,
- pp. 1-18.
-