Rogue Wave Banner

Click on the banner to return to the user guide home page.

©Copyright 1996 Rogue Wave Software

Using Templates Without the Standard Library

Several of the Tools.h++ templates, such as RWTValVector<T>, RWTPtrVector<T>, RWTIsvSlist<T>, and RWTIsvDlist<T>, are not based on the Standard C++ Library. You can use them on any of our certified platforms. Also, as mentioned previously in the Introduction, you can use many of the so-called standard library-based templates without the Standard C++ Library, as long as you keep to a subset of the full interface.

Keeping the Standard C++ Library in Mind for Portability

The restricted subset interfaces are almost fully upward compatible with their corresponding standard library-based interfaces. The major difference you will find is that some collections take a different number of template parameters, depending on which underlying implementation they are using. For example, when RWTPtrHashSet is used with the Standard C++ Library, it takes three template arguments as described in Hash Functions and Equalitors above. However, when that same class is used without the Standard C++ Library, the restricted interface calls for only one template parameter, namely the type of item being contained. To help you write portable code that works with or without the Standard C++ Library, Tools.h++ provides two macros:

  1. Use the first macro, RWDefHArgs(T), standing for Rogue Wave Default Hash Arguments, for the hash-based template collections. For example, by declaring:

  2. RWTPtrHashSet<int RWDefHArgs(int)> hset;

  3. you declare a hash-based set that will have the same semantics whether or not the Standard C++ Library is present. Note that you should not use a comma between the element type and the macro. Without the Standard C++ Library, the macro expands to nothing and it is as if you had declared:

  4. RWTPtrHashSet<int> hset;

  5. However, as soon as the Standard C++ Library becomes available, the macro expands as follows:

  6. RWTPtrHashSet<int ,RWTHasher<int>, equal_to<int> > hset;

  7. This declaration satisfies the full requirement of the standard library-based interface for all three parameters, and keeps the semantics consistent with the alternative non standard-library based implementation.

  8. The second macro, RWDefCArgs(T), is similar to the first. Standing for Rogue Wave Default Comparison Arguments, RWDefCArgs(T)is available for use with RWTPtrSortedVector and RWTValSortedVector. For example:

  9. RWTValSortedVector<int RWDefCArgs(int)> srtvec;

  10. is a portable declaration that will work with or without the Standard C++ Library. Again, do not use a comma to separate the element type from the macro.

An Example

Let's start with a simple example that uses RWTValVector<T>, one of the classes that is not based on the Standard C++ Library.

#include <rw/tvvector.h>            // 1

main() {
    RWTValVector<double> vec(20, 0.0);                     // 2

    int i;
    for (i=0; i<10; i++)     vec[i] = 1.0;                 // 3
    for (i=11; i<20; i++)    vec(i) = 2.0;                 // 4

    vec.reshape(30);                                       // 5
    for (i=21; i<30; i++)    vec[i] = 3.0;                 // 6
    return 0;
    }
 

Each program line is detailed below.

//1This is where the template for RWTValVector<T> is defined.
//2A vector of doubles, 20 elements long and initialized to 0.0, is declared and defined.
//3The first 10 elements of the vector are set to 1.0. Here, RWValVector<double>::operator[](int) has been used. This operator always performs a bounds check on its argument.
//4The next 10 elements of the vector are set to 2.0. In this case, RWValVector<double>::operator()(int) has been used. This operator generally does not perform a bounds check.
//5Member function reshape(int) changes the length of the vector.
//6Finally, the last 10 elements are initialized to 3.0.

Another Example

The second example involves a hashing dictionary. By using the macro RWDefHArgs(T) when you declare the hashing dictionary, you insure that your code is portable with or without access to the Standard C++ Library.

#include <rw/tvhdict.h>
#include <rw/cstring.h>
#include <rw/rstream.h>
#include <iomanip.h>

class Count {                                                  // 1
  int  N;
public:
  Count() :    N(0) { }                                        // 2
  int  operator++()  { return ++N; }                           // 3
  operator   int() { return N; }                                 // 4
};

unsigned hashString ( const RWCString& str )                   // 5
  { return str.hash(); }

main() {

  RWTValHashDictionary<RWCString,
                       Count  /* Note: no comma here! */
                       RWDefHArgs(RWCString)> hmap(hashString); //6


  RWCString token;
  while ( cin >> token )                                       // 7
    ++hmap[token];                                             // 8

  RWTValHashDictionaryIterator<RWCString,Count> next(hmap);    // 9

  cout.setf(ios::left, ios::adjustfield);                     // 10
  while ( ++next )                                            // 11
    cout << setw(20) << next.key()
         << " " << setw(10) << next.value() << endl;          // 12

  return 0;
}
 

Program Input:
How much wood could a woodchuck chuck if a woodchuck could chuck wood ?

Program Output:
much                 1
wood                 2
a                    2
if                   1
woodchuck            2
could                2
chuck                2
How                  1
?                    1

In the code above, the problem is to read an input file, break it up into tokens separated by white space, count the number of occurrences of each token, and then print the results. The general approach is to use a dictionary to map each token to its respective count. Here's a line-by-line description:

//1This is a class used as the value part of the dictionary.
//2A default constructor is supplied that zeros out the count.
//3We supply a prefix increment operator. This will be used to increment the count in a convenient and pleasant way.
//4A conversion operator is supplied that allows Count to be converted to an int. This will be used to print the results. Alternatively, we could have supplied an overloaded operator<<() to teach a Count how to print itself, but this is easier.
//5This is a function that must be supplied to the dictionary constructor. Its job is to return a hash value given an argument of the type of the key. Note that Tools.h++ supplies static hash member functions for classes RWCString, RWDate, RWTime, and RWWString that can be used in place of a user-supplied function. To keep the example general, we chose a user-defined function rather than one of the static hash member functions defined by Tools.h++.
//6Here the dictionary is constructed. Given a key, the dictionary can be used to look up a value. In this case, the key will be of type RWCString, the value of type Count. The constructor requires a single argument: a pointer to a function that will return a hash value, given a key. This function was defined on line 5 above. Note that we used the RWDefHArgs(T) macro to ensure that the program will be portable among platforms with and without the Standard C++ Library.
//7Tokens are read from the input stream into an RWCString. This will continue until an EOF is encountered. How does this work? The expression cin >> token reads a single token and returns an ostream&. Class ostream has a type conversion operator to void*, which is what the while loop will actually be testing. Operator void* returns this if the stream state is "good", and zero otherwise. Because an EOF causes the stream state to turn to "not good", the while loop will be broken when an EOF is encountered. See the RWCString entry in the Class Reference, and the ios entry in the class reference guide that comes with your compiler.
//8Here's where all the magic occurs. Object map is the dictionary. It has an overloaded operator[] that takes an argument of the type of the key, and returns a reference to its associated value. Recall that the type of the value is a Count. Hence, map[token] will be of type Count. As we saw on line 3, Count has an overloaded prefix increment operator. This is invoked on the Count, thereby increasing its value.

What if the key isn't in the dictionary? Then the overloaded operator[] will insert it, along with a brand new value built using the default constructor of the value's class. This was defined on line 2 to initialize the count to zero.
//9Now it comes time to print the results. We start by defining an iterator that will sweep over the dictionary, returning each key and value.
//10The field width of the output stream is adjusted to make things pretty.
//11The iterator is advanced until it reaches the end of the collection class. For all template iterators, the prefix increment operator advances the iterator, then tests whether it has gone past the end of the collection class.
//12The key and value at the position of the iterator are printed.

Previous file Table of Contents Next file