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 String { // stuff }; template <> class String { // 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 vector { // stuff }; for managing vectors of objects. A partial specialization of this template might look like: // primary template template class vector { // stuff }; // partial specialization template class vector { // 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 A {}; template class A {}; A a1; A 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 vector { template friend void f(vector); // stuff }; // partial specialization template class vector { template friend void f(vector); // stuff }; Without partial ordering of function templates, that is, preferring the friend function "f(vector)" 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 void f(T) {} template 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 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 #include 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 #include #include using namespace std; const int N = 100; void main() { vector iv(N); iv[50] = 37; vector::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