Boost logo

Boost :

From: Lewis Hyatt (lhyatt_at_[hidden])
Date: 2005-10-12 18:39:54


Hi All,

        I am in the middle of writing a large body of numerical code for data
analysis and have found the boost library very useful for a number of
things. I do a lot of work with std::map and with containers of
std::pair objects, and one thing I've always felt annoyed with is the
difficulty of interfacing a value_type of std::pair with the STL
algorithms. Frequently, for instance, it is nice to represent data as a
std::list< std::pair<double,double> > and then to be able to work with
the first and second coordinates independently and pass them to
std::accumulate() or whatever. The SGI extensions select1st() and
select2nd() are somewhat useful but also non-standard, and they
frequently require memory-wasting buffers to store only the first or
second elements.

I have a relatively simple system for solving this problem and it
strikes me as the kind of quick thing that might be worth including in
boost. The idea is to define a template class,

template<typename Iterator> class first_iterator_t {
        Iterator pair_iter;
public:
        first_iterator_t(Iterator const&);
        /*...*/
};

which overloads operator*() and operator->() to access the element named
"first" of the object returned by Iterator::operator*(). (With something
analagous for second_iterator_t.) A function named first_iterator()
provides a convenient creation function a-la std::make_pair().

That's it for the most part, the class only needs to provide the
required iterator interface which mostly consists of just calls to
Iterator::operator functions. There is also the need to define the
appropriate iterator_traits typedefs. There is a small issue of deducing
whether the iterator needs to be a const iterator or not, which can be
solved with partial specialization of a second template class containing
nested typedefs.

The end result is that something like this is now conveniently available:

map<int, double> m;
m[1] = 0.1; m[2]=0.2; m[5]=0.5;

//prints: 1 2 5
copy(first_iterator(m.begin()), first_iterator(m.end()),
ostream_iterator<int>(cout, "\t"));

//prints: 0.1 0.2 0.5
copy(second_iterator(m.begin()), second_iterator(m.end()),
ostream_iterator<double>(cout, "\t"));

I don't see a way to do this otherwise without resorting to something
like select1st(), and that also requires the use of std::transform(),
which I find distasteful since the required operation is really just a
simple copy.

So anyway do you think this is useful enough to possibly include in
boost somewhere, or is it too trivial? I have what I believe to be
correct code, which could be made boost-ready with little effort.

Thanks for your advice!

-Lewis


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk