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

Combining STL containers

When using a thesaurus, you want to know all the words that are similar to a particular word. When you look up a word, then, you want a list of words as the result. Here, the multi containers (multimap or multiset) are not appropriate. The solution is to combine containers, which is easily done using the STL. Here, we need a tool that turns out to be a powerful general concept, which is a map that associates a string with a vector:

//: C07:Thesaurus.cpp
// A map of vectors.
#include <map>
#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <ctime>
#include <cstdlib>
using namespace std;
 
typedef map<string, vector<string> > Thesaurus;
typedef pair<string, vector<string> > TEntry;
typedef Thesaurus::iterator TIter;
 
// Name lookup work-around:
namespace std {
ostream& operator<<(ostream& os,const TEntry& t) {
os << t.first << ": ";
copy(t.second.begin(), t.second.end(),
ostream_iterator<string>(os, " "));
return os;
}
}
 
// A generator for thesaurus test entries:
class ThesaurusGen {
static const string letters;
static int count;
public:
int maxSize() { return letters.size(); }
TEntry operator()() {
TEntry result;
if(count >= maxSize()) count = 0;
result.first = letters[count++];
int entries = (rand() % 5) + 2;
for(int i = 0; i < entries; i++) {
int choice = rand() % maxSize();
char cbuf[2] = { 0 };
cbuf[0] = letters[choice];
result.second.push_back(cbuf);
}
return result;
}
};
 
int ThesaurusGen::count = 0;
const string ThesaurusGen::letters("ABCDEFGHIJKL"
"MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
 
// Ask for a "word" to look up:
string menu(Thesaurus& thesaurus) {
while(true) {
cout << "Select a \"word\", 0 to quit: ";
for(TIter it = thesaurus.begin();
it != thesaurus.end(); it++)
cout << (*it).first << ' ';
cout << endl;
string reply;
cin >> reply;
if(reply.at(0) == '0') exit(0); // Quit
if(thesaurus.find(reply) == thesaurus.end())
continue; // Not in list, try again
return reply;
}
}
 
int main() {
srand(time(0)); // Seed the random number generator
Thesaurus thesaurus;
// Fill with 10 entries:
generate_n(inserter(thesaurus, thesaurus.begin()),
10, ThesaurusGen());
// Print everything:
copy(thesaurus.begin(), thesaurus.end(),
ostream_iterator<TEntry>(cout, "\n"));
// Create a list of the keys:
string keys[10];
int i = 0;
for(TIter it = thesaurus.begin();
it != thesaurus.end(); it++)
keys[i++] = (*it).first;
for(int count = 0; count < 10; count++) {
// Enter from the console:
// string reply = menu(thesaurus);
// Generate randomly
string reply = keys[rand() % 10];
vector<string>& v = thesaurus[reply];
copy(v.begin(), v.end(),
ostream_iterator<string>(cout, " "));
cout << endl;
}
} ///:~
 

A Thesaurus maps a string (the word) to a vector<string> (the synonyms). A TEntry is a single entry in a Thesaurus. By creating an ostream operator<< for a TEntry, a single entry from the Thesaurus can easily be printed (and the whole Thesaurus can easily be printed with copy( )). Notice the very strange placement of the stream inserter: we put it inside the std namespace![113] This operator<<( ) function is used by ostream_iterator in the first call to copy( ) in main( ) above. When the compiler instantiates the needed ostream_iterator specialization, according to the rules of argument-dependent lookup (ADL) it only looks in std because that is where all the arguments to copy( ) are declared. If we declared our inserter in the global namespace (by removing the namespace block around it), then it would not be found. By placing it in std we enable ADL to find it.

The ThesaurusGen creates words (which are just single letters) and synonyms for those words (which are just other randomly chosen single letters) to be used as thesaurus entries. It randomly chooses the number of synonym entries to make, but there must be at least two. All the letters are chosen by indexing into a static string that is part of ThesaurusGen.

In main( ), a Thesaurus is created, filled with 10 entries and printed using the copy( ) algorithm. The menu( ) function asks the user to choose a word to look up by typing the letter of that word. The find( ) member function discovers whether the entry exists in the map. (Remember, you don t want to use operator[ ], which will automatically make a new entry if it doesn t find a match!) If so, operator[ ] fetches out the vector<string> that is displayed. The selection of the reply string is generated randomly, to allow automated testing.

Because templates make the expression of powerful concepts easy, you can take this concept much further, creating a map of vectors containing maps, and so on. For that matter, you can combine any of the STL containers this way.

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

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