Microsoft Foundation Classes                           Microsoft Corporation
Technical Notes              

#4 : Template Classes and MFC

This note describes MFC template class issues and the MFC "templdef" 
template expansion sample code.
=============================================================================
The Problem
===========

There has long been recognized within the C++ community the need for
template classes -- classes that can be instantiated based on an
exact type specified by the user.  A common example would be a linked
list class -- a linked list of what type of object?  With template
classes the user of the class can specify that:  "I want a linked
list of CFoo objects."

-----------------------------------------------------------------------------
The templdef sample
===================

While a syntax for template classes has been generally agreed-upon
within the C++ community, exact details have not been worked out.
We found it useful to provide template classes to the user in the
interim.  The approach decided upon was to use a syntax for our
template classes based on that generally used within the C++
community.  This syntax is then expanded and modified slightly by a
simple template expander called "templdef."  For this expansion the
user specifies a "typedef'ed" name to be used as an alternative to
the template_class<type_specifier> class name.

With this approach the Foundation user can begin to write template
classes following the generally agreed-upon syntax for C++
templates.  This code can be ported to the eventual final agreed-upon
syntax when the ANSI C++ report is issued.  Also, the Foundation user
can read the Foundation template classes as general examples of how
one writes templates.  And the templdef source code provides an
example of how one can use the Foundation classes.

In order to provide easily readable output from the templdef template
expander, we have chosen to leave comments in the expanded output,
and to substitute-in textually the type parameters the user
specifies.  If the user desires to expand template classes over
complicated types, use of typedef'ed type names is suggested for
template parameters.

We advise users wanting to experiment with template classes and
templdef should first write and completely debug a non-template
version of their class.  For example, first write a
linked-list-of-CFoos class.  When you have that working, then
generalize your linked-list-of-CFoos class to a
linked-list-of-whatever template class.  By taking this approach, you
introduce the complicating factor of "template <class CXyz>" syntax
*after* you have an already working linked-list class.  Finally, you
should expect some small changes between the template classes you
write today, and the final syntax agreed upon by the ANSI-C++
committee.

A good way to get started is by examining the .ctt template classes
provided with Foundation (found in mfc\sample\templdef subdirectory). 
The mkcoll.bat file gives examples of the command line syntax of the
templdef tool.  The general form of the command line syntax is
modeled after a C++ typedef of the equivalent template class.  As a
hypothetical exammple:

typedef CArray<CString> CStringArray;

becomes:

templdef "CArray<CString> CStringArray" array.ctt strarray.h strarray.cpp

Note: The actual Foundation template classes are slightly more complicated
than this example, taking a number of boolean constant template
parameters which allow several slightly different flavors of arrays
to be expanded.

-----------------------------------------------------------------------------
Template source formatting
==========================

A source file containing a templdef template class is divided into
three sections.

The first section consists of comments, usage instructions, copyright
notices and the like.  This first section is stripped by templdef and
is not emitted.  The second section starts with a special:

//$DECLARE_TEMPLATE

directive, after which the template class declaration appears. 
templdef processes this section to result in the output .h file. 
After the declaration section comes a special:

//$IMPLEMENT_TEMPLATE

directive followed by any member function definitions required by the
template class.  This final section is processed into the resulting 
.cpp output file.

Friend functions, static member definitions, and the like can be
included as needed in these sections.  Other than #if/#else/#endif
sections expanded on a template parameter (see next section),
preprocessor commands are left unexpanded in the output files.  This
permits additional processing by the native compiler preprocessor.

One restriction of the templdef implementation is that the first
occurance of a template declaration (typically *the* template class
declaration) defines *all* name-wise correspondences between template
formal parameters and actual parameters throughout the template class
file.  Thus template parameter names must be used consistently
throughout all template declarations and definitions in the template
class file.  This approach is consistent with the fact that you are
expanding on only one particular, out of n possible, template
possibilities.

-----------------------------------------------------------------------------
Template parameters and special #if/#else/#endif processing
===========================================================

Templdef template parameters can either be types, or can be
compile-time constant expressions.  In particular, if a template
parameter is "0" or "1", then templdef will evaluate (only)
#if/#else/#endif statements based on that constant parameter, and
emit only those lines of code corresponding to the true condition. 
Again, see mkcoll.bat and the Foundation template classes for
examples of how to use this feature.  

The #if/#else/#endif expansion depends on having exactly the manifest
constant "1" or "0" as a template parameter.  For example, if you
were to say "TRUE" or "FALSE" instead, then templdef would leave in
the #if/#else/#endif expressions for the preprocessing phase of the
compiler to expand later.  Also, this templdef evaluation does not
take into account nested #if/#else statements -- either make sure
your expansion corresponds to an inner-most nesting and use "0" or
"1" as your boolean constant template parameter, or say "FALSE" or
"TRUE" and let the compiler's preprocessing phase do the
#if/#else/#endif expansion later.  Another limitation on templdef's
capabilities in this area is that it expects #if/#else/#endif
statements to be written following the common convention of no
intervening space after the '#' sign.  If you need to write # .... if
/ # .... else / # .... endif then let the compiler's preprocessor
handle the job instead.

-----------------------------------------------------------------------------
