Issue #020
February, 1997


Contents:

Partial Specializations of Class Templates
Partial Ordering of Function Templates
Notes From ANSI/ISO - More on terminate() and unexpected()
Notes From ANSI/ISO - Follow-up on Placement New/Delete
Notes From ANSI/ISO - Current Draft Standard Now Publicly Available
Introduction to STL Part 7 - Iterators


PARTIAL SPECIALIZATIONS OF CLASS TEMPLATES

In issue #012 we talked about template specialization, for example:

        template <class T> class String {
                // stuff
        };

        template <> class String<char> {
                // stuff
        };

In this example we have a String template, and a "special case" where
the type argument to the template is "char".

A relatively new feature (in terms of availability) generalizes this
feature a bit, and is known as partial specialization of class
templates.  For example, in the standard library for C++ there is a
template:

        template <class T, class Allocator> class vector {
                // stuff
        };

for managing vectors of objects.  A partial specialization of this
template might look like:

        // primary template

        template <class T, class Allocator> class vector {
                // stuff
        };

        // partial specialization

        template <class Allocator> class vector<bool, Allocator> {
                // stuff
        };

One type parameter has been bound to "bool", and the other is still
unbound and may be specified by the user (in this example, to specify
a type of storage allocator).  In this case, the specialization allows
for use of a packed representation of the vector.

With partial specializations there is an issue with which template is
to be preferred in a given case.  For example:

        template <class T> class A {};

        template <class T> class A<T*> {};

        A<double> a1;

        A<int*> a2;

In this example, "double" can only match the first template, while
"int*" could match either.  But "T*" is considered to be more
specialized than "T", and so the second template is used for "int*".

There are several additional angles on matching that you may wish to
investigate for yourself.  Compilers may not yet have this feature.
See below for details of where to get a copy of the current draft
standard.


PARTIAL ORDERING OF FUNCTION TEMPLATES

Somewhat related to partial class specializations is partial ordering
of function templates.  Suppose that you have the vector example from
the previous section, with one additional feature:

        // primary template

        template <class T, class Allocator> class vector {
                template <class U, class W> friend void f(vector<U, W>);
                // stuff
        };

        // partial specialization

        template <class Allocator> class vector<bool, Allocator> {
                template <class U> friend void f(vector<bool, U>);
                // stuff
        };

Without partial ordering of function templates, that is, preferring
the friend function "f(vector<bool, U>)" in the specialized case, this
example would be ambiguous, and there would be no way to determine
which function template to call.

Like the example in the previous section, there are various rules that
are applied to order templates and choose the appropriate one.  For
example:

        template <class T> void f(T) {}

        template <class T> void f(T*) {}

        void g()
        {
                int* p = 0;

                f(12.34);               // calls first template

                f(p);                   // calls second one
        }

As with class templates, there is a notion of one function template
being "more specialized" than another.


NOTES FROM ANSI/ISO - MORE ON TERMINATE() AND UNEXPECTED()
Jonathan Schilling, jls@sco.com

In C++ Newsletter #019 the terminate handler, the unexpected handler,
and the standard library function uncaught_exception() were
introduced.  

The standards committee recently decided what values 
uncaught_exception() should return when called from these handlers:
false from unexpected() and true from terminate().

The latter ruling is somewhat counter-intuitive, because an exception
is considered "caught" in the standard when terminate() is called, so
logically uncaught_exception() should return the inverse.  The rationale
for the decision was that uncaught_exception() should include the case
where terminate has been called by the implementation.  Some committee 
members argued that it should return false, or that the value should be 
left undefined.  But at the end of the day this is a good example of 
the kind of minutiae a standards committee must deal with, because if
you consider that the purpose of uncaught_exception() is to help
keep you out of terminate(), then if you're already in terminate() 
anyway it pretty much doesn't much matter what it returns.

Note however that these rules only apply when unexpected() and
terminate() are called by the implementation.  When direct user calls
are made to these functions (see again Newsletter #019),
uncaught_exception() will return false unless the direct user call was
made from code executing as part of an exception.  In the case of
terminate() this difference between implementation calls and direct
calls might complicate simulation testing of error conditions.


NOTES FROM ANSI/ISO - FOLLOW-UP ON PLACEMENT NEW/DELETE
Jonathan Schilling, jls@sco.com

Also introduced in Newsletter #019 were placement new and placement 
delete.  In addition to the language providing this general capability, 
the C++ standard library also provides a specific instance for void*:

        void* operator new(size_t, void*);

        void operator delete(void*, void*);

These are accessed by saying:

        #include <new>

These functions are defined to do nothing (though new returns its
argument).  Their purpose is to allow construction of an object at a
specific address, which is often useful in embedded systems and other
low-level applications: 

        const unsigned long MEMORY_MAP_IO_AREA = 0xf008;

        ...

        Some_Class* p = new ((void*) MEMORY_MAP_IO_AREA) Some_Class();

Based on a fairly recent decision of the standards committee, this
definition of placement new/delete for void* is reserved by the
library, and cannot be replaced by the user (unlike the normal global
operator new, which can be).  The library also defines a similar
placement new/delete for allocating arrays at a specific address.


NOTES FROM ANSI/ISO - CURRENT DRAFT STANDARD NOW PUBLICLY AVAILABLE
Jonathan Schilling, jls@sco.com

In C++ Newsletter #018 it was mentioned that the C++ standards 
committee has recently issued its "second Committee Draft" (CD2) of
the standard, with an associated public review period, but that 
due to ISO policy the draft would not be available without charge.

ISO has just now reversed this policy, and two Web sites now have
information on how to download the draft and to make public review
comments:

        http://www.setech.com/x3.html

        http://www.maths.warwick.ac.uk/c++/pub/

The ANSI public review period ends on March 18, so if you're interested
in submitting a comment, better do it quickly!


INTRODUCTION TO STL PART 7 - ITERATORS

In previous issues we've covered various STL container types such as
lists and sets.  With this issue we'll start discussing iterators.
Iterators in STL are mechanisms for accessing data elements in
containers and for cycling through lists of elements.

Let's start by looking at an example:

        #include <algorithm>
        #include <iostream>

        using namespace std;

        const int N = 100;

        void main()
        {
                int arr[N];

                arr[50] = 37;

                int* ip = find(arr, arr + N, 37);
                if (ip == arr + N)
                        cout << "item not found in array\n";
                else
                        cout << "found at position " << ip - arr << "\n";
        }

In this example, we have a 100-long array of ints, and we want to
search for the location in the array where a particular value (37) is
stored.  To do this, we call find() and specify the starting point
("arr") and ending point ("arr + N") in the array, along with the
value to search for (37).

An index is returned to the value in the array, or to one past the end
of the array if the value is not found.  In this example, "arr", "arr
+ N", and "ip" are iterators.

This approach works fine, but requires some knowledge of pointer
arithmetic in C++.  Another approach looks like this:

        #include <algorithm>
        #include <vector>
        #include <iostream>

        using namespace std;

        const int N = 100;

        void main()
        {
                vector<int> iv(N);

                iv[50] = 37;

                vector<int>::iterator iter = find(iv.begin(), iv.end(), 37);
                if (iter == iv.end())
                        cout << "not found\n";
                else
                        cout << "found at " << iter - iv.begin() << "\n";
        }

This code achieves the same end, but is at a higher level.  Instead of
an actual array of ints, we have a vector of ints, and vector is a
higher-level construct than a primitive C/C++ array.  For example, a
vector has within in it knowledge of how long it is, so that we can say
"iv.end()" to refer to the end of the array, without reference to N.

In future issues we will be looking at several additional examples of
iterator usage.


ACKNOWLEDGEMENTS

Thanks to Nathan Myers, Eric Nagler, David Nelson, Jonathan Schilling,
and Elaine Siegel for help with proofreading.


SUBSCRIPTION INFORMATION / BACK ISSUES

To subscribe to the newsletter, send mail to majordomo@world.std.com
with this line as its message body:

subscribe c_plus_plus

Back issues are available via FTP from:

        rmi.net /pub2/glenm/newslett

or on the Web at:

        http://rainbow.rmi.net/~glenm

There is also a Java newsletter.  To subscribe to it, say:

subscribe java_letter

using the same majordomo@world.std.com address.

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

Copyright (c) 1997 Glen McCluskey.  All Rights Reserved.

This newsletter may be further distributed provided that it is copied
in its entirety, including the newsletter number at the top and the
copyright and contact information at the bottom.

Glen McCluskey & Associates
Professional C++ Consulting
Internet: glenm@glenmccl.com
Phone: (800) 722-1613 or (970) 490-2462
Fax: (970) 490-2463
FTP: rmi.net /pub2/glenm/newslett (for back issues)
Web: http://rainbow.rmi.net/~glenm
