Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

A practical example

You can easily derive from a class template, and you can create a new template that instantiates and inherits from an existing template. If the vector template does most everything you want, for example, but in a certain application you d also like a version that can sort itself, you can easily reuse the vector code. The following example derives from vector<T> and adds sorting. Note that deriving from vector, which doesn t have a virtual destructor, would be dangerous if we needed to perform cleanup in our destructor.

//: C05:Sortable.h
// Template specialization.
#ifndef SORTABLE_H
#define SORTABLE_H
#include <cstring>
#include <cstddef>
#include <string>
#include <vector>
using std::size_t;
 
template<class T>
class Sortable : public std::vector<T> {
public:
void sort();
};
 
template<class T>
void Sortable<T>::sort() { // A simple sort
for(size_t i = this->size(); i > 0; --i)
for(size_t j = 1; j < i; ++j)
if(this->at(j-1) > this->at(j)) {
T t = this->at(j-1);
this->at(j-1) = this->at(j);
this->at(j) = t;
}
}
 
// Partial specialization for pointers:
template<class T>
class Sortable<T*> : public std::vector<T*> {
public:
void sort();
};
 
template<class T>
void Sortable<T*>::sort() {
for(size_t i = this->size(); i > 0; --i)
for(size_t j = 1; j < i; ++j)
if(*this->at(j-1) > *this->at(j)) {
T* t = this->at(j-1);
this->at(j-1) = this->at(j);
this->at(j) = t;
}
}
 
// Full specialization for char*
// (Made inline here for convenience -- normally you would
// place the function body in a separate file and only
// leave the declaration here).
template<> inline void Sortable<char*>::sort() {
for(size_t i = this->size(); i > 0; --i)
for(size_t j = 1; j < i; ++j)
if(std::strcmp(this->at(j-1), this->at(j)) > 0) {
char* t = this->at(j-1);
this->at(j-1) = this->at(j);
this->at(j) = t;
}
}
#endif // SORTABLE_H ///:~
 

The Sortable template imposes a restriction on all but one of the classes for which it is instantiated: they must contain a > operator. It works correctly only with non-pointer objects (including objects of built-in types). The full specialization compares the elements using strcmp( ) to sort vectors of char* according to the null-terminated strings to which they refer. The use of this-> above is mandatory[61] and is explained in the section entitled Name lookup issues later in this chapter.[62]

Here s a driver for Sortable.h that uses the randomizer introduced earlier in the chapter:

//: C05:Sortable.cpp
//{-bor} (Because of bitset in Urand.h)
// Testing template specialization.
#include <cstddef>
#include <iostream>
#include "Sortable.h"
#include "Urand.h"
using namespace std;
 
#define asz(a) (sizeof a / sizeof a[0])
 
char* words[] = { "is", "running", "big", "dog", "a", };
char* words2[] = { "this", "that", "theother", };
 
int main() {
Sortable<int> is;
Urand<47> rnd;
for(size_t i = 0; i < 15; ++i)
is.push_back(rnd());
for(size_t i = 0; i < is.size(); ++i)
cout << is[i] << ' ';
cout << endl;
is.sort();
for(size_t i = 0; i < is.size(); ++i)
cout << is[i] << ' ';
cout << endl;
 
// Uses the template partial specialization:
Sortable<string*> ss;
for(size_t i = 0; i < asz(words); ++i)
ss.push_back(new string(words[i]));
for(size_t i = 0; i < ss.size(); ++i)
cout << *ss[i] << ' ';
cout << endl;
ss.sort();
for(size_t i = 0; i < ss.size(); ++i) {
cout << *ss[i] << ' ';
delete ss[i];
}
cout << endl;
 
// Uses the full char* specialization:
Sortable<char*> scp;
for(size_t i = 0; i < asz(words2); ++i)
scp.push_back(words2[i]);
for(size_t i = 0; i < scp.size(); ++i)
cout << scp[i] << ' ';
cout << endl;
scp.sort();
for(size_t i = 0; i < scp.size(); ++i)
cout << scp[i] << ' ';
cout << endl;
} ///:~
 

Each of the template instantiations above uses a different version of the template. Sortable<int> uses the primary template. Sortable<string*> uses the partial specialization for pointers. Last, Sortable<char*> uses the full specialization for char*. Without this full specialization, you could be fooled into thinking that things were working correctly because the words array would still sort out to a big dog is running since the partial specialization would end up comparing the first character of each array. However, words2 would not sort correctly.

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire