Copy Link
Add to Bookmark
Report

C++ Newsletter/Tutorial Issue 20

eZine's profile picture
Published in 
CPPNL
 · 2 years ago

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

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT