
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

Lewis Hyatt <lhyatt@Princeton.EDU> writes:
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().
Sounds like a job for transform_iterator. http://www.boost.org/libs/iterator/doc/transform_iterator.html -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Lewis Hyatt <lhyatt@Princeton.EDU> writes:
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().
Sounds like a job for transform_iterator.
http://www.boost.org/libs/iterator/doc/transform_iterator.html
transform_iterator<(&_1)->first, Iterator>? Interesting, it could save me a couple of lines here and there... (every little bit helps)

Simon Buchan <simon@hand-multimedia.co.nz> writes:
David Abrahams wrote:
Lewis Hyatt <lhyatt@Princeton.EDU> writes:
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().
Sounds like a job for transform_iterator.
http://www.boost.org/libs/iterator/doc/transform_iterator.html
transform_iterator<(&_1)->first, Iterator>?
Not quite; an expression like that never matches a type template parameter. struct get_first { template <class T> typename T::first_type& operator()(T& x) const { return x.first; } template <class T> typename T::first_type const& operator()(T const& x) const { return x.first; } }; // similar get_second transform_iterator<get_first, Iterator>
Interesting, it could save me a couple of lines here and there... (every little bit helps)
Considering that most user-defined "iterators" are actually wrong for reasons described in http://www.boost.org/libs/iterator/doc/facade-and-adaptor.html#motivation, it could save you more than that. :) -- Dave Abrahams Boost Consulting www.boost-consulting.com

I resurect an old post : David Abrahams a écrit :
Simon Buchan <simon@hand-multimedia.co.nz> writes:
The idea is to define a template class, [...] 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(). [...] struct get_first { template <class T> typename T::first_type& operator()(T& x) const { return x.first; }
template <class T> typename T::first_type const& operator()(T const& x) const { return x.first; } };
// similar get_second
transform_iterator<get_first, Iterator>
Hello, I think this kind of adapter is quite usefull and of broad usage, and I think it should be part of the iterators provided by default in the Iterator library, just like indirect_iterator. Or at least put is as a real life example of what can be done with transform_iterator. Regards, -- Loïc

Loïc Joly <loic.joly@reportive.com> writes:
Hello,
I think this kind of adapter is quite usefull and of broad usage, and I think it should be part of the iterators provided by default in the Iterator library, just like indirect_iterator. Or at least put is as a real life example of what can be done with transform_iterator.
Patches (including tests and documentation) are always welcome. -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (4)
-
David Abrahams
-
Lewis Hyatt
-
Loïc Joly
-
Simon Buchan