Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
B.Eckel - Thinking in C++, Vol.2, 2nd edition.pdf
Скачиваний:
50
Добавлен:
08.05.2013
Размер:
2.09 Mб
Скачать

first and use a profiler to discover bottlenecks), then you can use the counted-handle approach shown in Chapter XX so that you are only passing around small, lightweight objects.

Of course, you can also iterate through a set or map and operate on each of its objects. This will be demonstrated in later examples.

Generators and fillers for associative containers

You’ve seen how useful the fill( ), fill_n( ), generate( ) and generate_n( ) function templates in <algorithm> have been for filling the sequential containers (vector, list and deque) with data. However, these are implemented by using operator= to assign values into the sequential containers, and the way that you add objects to associative containers is with their respective insert( ) member functions. Thus the default “assignment” behavior causes a problem when trying to use the “fill” and “generate” functions with associative containers.

One solution is to duplicate the “fill” and “generate” functions, creating new ones that can be used with associative containers. It turns out that only the fill_n( ) and generate_n( ) functions can be duplicated (fill( ) and generate( ) copy in between two iterators, which doesn’t make sense with associative containers), but the job is fairly easy, since you have the <algorithm> header file to work from (and since it contains templates, all the source code is there):

//: C04:assocGen.h

//The fill_n() and generate_n() equivalents

//for associative containers.

#ifndef ASSOCGEN_H #define ASSOCGEN_H

template<class Assoc, class Count, class T> void

assocFill_n(Assoc& a, Count n, const T& val) { while(n-- > 0)

a.insert(val);

}

template<class Assoc, class Count, class Gen> void assocGen_n(Assoc& a, Count n, Gen g) {

while(n-- > 0) a.insert(g());

}

#endif // ASSOCGEN_H ///:~

Chapter 15: Multiple Inheritance

236

You can see that instead of using iterators, the container class itself is passed (by reference, of course, since you wouldn’t want to make a local copy, fill it, and then have it discarded at the end of the scope).

This code demonstrates two valuable lessons. The first lesson is that if the algorithms don’t do what you want, copy the nearest thing and modify it. You have the example at hand in the STL header, so most of the work has already been done.

The second lesson is more pointed: if you look long enough, there’s probably a way to do it in the STL without inventing anything new. The present problem can instead be solved by using an insert_iterator (produced by a call to inserter( )), which calls insert( ) to place items in the container instead of operator=. This is not simply a variation of front_insert_iterator (produced by a call to front_inserter( )) or back_insert_iterator (produced by a call to back_inserter( )), since those iterators use push_front( ) and push_back( ), respectively. Each of the insert iterators is different by virtue of the member function it uses for insertion, and insert( ) is the one we need. Here’s a demonstration that shows filling and generating both a map and a set (of course, it can also be used with multimap and multiset). First, some templatized, simple generators are created (this may seem like overkill, but you never know when you’ll need them; for that reason they’re placed in a header file):

//: C04:SimpleGenerators.h

//Generic generators, including

//one that creates pairs #include <iostream> #include <utility>

//A generator that increments its value: template<typename T>

class IncrGen { T i;

public:

IncrGen(T ii) : i (ii) {}

T operator()() { return i++; }

};

//A generator that produces an STL pair<>: template<typename T1, typename T2>

class PairGen { T1 i;

T2 j; public:

PairGen(T1 ii, T2 jj) : i(ii), j(jj) {} std::pair<T1,T2> operator()() {

return std::pair<T1,T2>(i++, j++);

}

Chapter 15: Multiple Inheritance

237

};

//A generic global operator<<

//for printing any STL pair<>: template<typename Pair> std::ostream& operator<<(std::ostream& os, const Pair& p) {

return os << p.first << "\t"

<<p.second << std::endl;

} ///:~

Both generators expect that T can be incremented, and they simply use operator++ to generate new values from whatever you used for initialization. PairGen creates an STL pair object as its return value, and that’s what can be placed into a map or multimap using insert( ).

The last function is a generalization of operator<< for ostreams, so that any pair can be printed, assuming each element of the pair supports a stream operator<<. As you can see below, this allows the use of copy( ) to output the map:

//: C04:AssocInserter.cpp

//Using an insert_iterator so fill_n() and

//generate_n() can be used with associative

//containers

#include "SimpleGenerators.h" #include <iterator>

#include <iostream> #include <algorithm> #include <set> #include <map>

using namespace std;

int main() { set<int> s;

fill_n(inserter(s, s.begin()), 10, 47); generate_n(inserter(s, s.begin()), 10,

IncrGen<int>(12)); copy(s.begin(), s.end(),

ostream_iterator<int>(cout, "\n"));

map<int, int> m; fill_n(inserter(m, m.begin()), 10,

make_pair(90,120)); generate_n(inserter(m, m.begin()), 10,

PairGen<int, int>(3, 9)); copy(m.begin(), m.end(),

Chapter 15: Multiple Inheritance

238

Соседние файлы в предмете Численные методы
  • #
    08.05.20133.99 Mб22A.Menezes, P.van Oorschot,S.Vanstone - HANDBOOK OF APPLIED CRYPTOGRAPHY.djvu
  • #
  • #
    08.05.20135.91 Mб24B.Eckel - Thinking in Java, 3rd edition (beta).pdf
  • #
  • #
    08.05.20136.09 Mб17D.MacKay - Information Theory, Inference, and Learning Algorithms.djvu
  • #
    08.05.20133.85 Mб15DIGITAL Visual Fortran ver.5.0 - Programmers Guide to Fortran.djvu
  • #
    08.05.20131.84 Mб12E.A.Lee, P.Varaiya - Structure and Interpretation of Signals and Systems.djvu