An iterator "points" to an element of an object

I admit that I had difficulty with a reasonable description of this. I can’t come up with a good term that accurately describes what I’m looking for. Perhaps this can be called a cutting iterator.

Let's say I have something like this:

struct S { int i; char *s; float f; }; std::vector<S> v(10); 

What I'm looking for is a way to create an iterator that points to a member of S I would like to pass it to something like std::min_element without creating a predicate in each case. Something that might look like this:

 std::min_element(slicing_iterator(v.begin(), S::f), slicing_iterator(v.end(), S::f)); 

Is there any template trick I could use to achieve this? Or perhaps it has already been done somewhere in Boost or in some other library?

+7
source share
4 answers

If you are looking for an iterator that converts S to S :: f, this can be done with boost (which can't be?):

 std::cout << *std::min_element( boost::make_transform_iterator(v.begin(), boost::bind(&S::f, _1)), boost::make_transform_iterator(v.end(), boost::bind(&S::f, _1)) ) << '\n'; 

test: https://ideone.com/jgcHr

But if you are looking for S for which S :: f is the smallest in the vector, the predicate is the most sensible approach.

+13
source

If you do not want to create a predicate function for each case, I would suggest not looking for a cutting operator, but implementing a predicate as a lambda function (using Boost or C ++ 0x). Here you will find a detailed explanation.

http://www.codeproject.com/KB/cpp/Sort.aspx

(This is roughly std::sort , but the comparison in std::min_element works the same.)

+2
source

Will something like this do the job?

 #include <algorithm> #include <iostream> #include <vector> struct S { int i; float f; S() : i(0), f(0.0f) {} S(int i_, float f_) : i(i_), f(f_) {} }; template <typename Iterator, typename T, typename M> class SlicingIterator : public std::iterator<typename Iterator::iterator_category,M> { private: Iterator m_it; MT::*m_m; public: SlicingIterator(const Iterator& it, MT::*m) : m_it(it), m_m(m) {} const M operator*() const { return (*m_it).*m_m; } bool operator!=(const SlicingIterator& rhs) const { return m_it != rhs.m_it; } SlicingIterator& operator++() { ++m_it; return *this; } bool operator<(const SlicingIterator& rhs) const { return m_it < rhs.m_it; } }; template <typename Iterator, typename T, typename M> SlicingIterator<Iterator,T,M> slicing_iterator(const Iterator& it, MT::*m) { return SlicingIterator<Iterator,T,M>(it, m); } int main() { std::vector<S> vec; vec.push_back(S(23,9)); vec.push_back(S(17,10)); std::copy(slicing_iterator(vec.begin(), &S::f), slicing_iterator(vec.end(), &S::f), std::ostream_iterator<float>(std::cout, " ")); return 0; } 
+2
source

In addition to what has already been suggested, you can do this in much the same way as your sample code.

Example:

 template< class IterT, class ObjT, class MemberT > class slicing_iterator; template< class IterT, class ObjT, class MemberT > inline bool operator==( const slicing_iterator<IterT,ObjT,MemberT>& a, const slicing_iterator<IterT,ObjT,MemberT>& b ); template< class IterT, class ObjT, class MemberT > inline bool operator!=( const slicing_iterator<IterT,ObjT,MemberT>& a, const slicing_iterator<IterT,ObjT,MemberT>& b ); template< class IterT, class ObjT, class MemberT > class slicing_iterator { IterT m_iter; MemberT ObjT::* m_member; public: slicing_iterator( IterT iter, MemberT ObjT::*member ) : m_iter(iter), m_member(member) { } slicing_iterator& operator++() { ++m_iter; return *this; } slicing_iterator& operator--() { --m_iter; return *this; } MemberT& operator*() { return static_cast<ObjT&>(*m_iter).*m_member; } const MemberT& operator*() const { return static_cast<const ObjT&>(*m_iter).*m_member; } MemberT* operator->() { return &m_iter->*m_member; } const MemberT* operator->() const { return &m_iter->*m_member; } private: friend bool operator== <IterT,ObjT,MemberT>( const slicing_iterator<IterT,ObjT,MemberT>& a, const slicing_iterator<IterT,ObjT,MemberT>& b ); friend bool operator!= <IterT,ObjT,MemberT>( const slicing_iterator<IterT,ObjT,MemberT>& a, const slicing_iterator<IterT,ObjT,MemberT>& b ); }; template< class IterT, class ObjT, class MemberT > inline bool operator==( const slicing_iterator<IterT,ObjT,MemberT>& a, const slicing_iterator<IterT,ObjT,MemberT>& b ) { return a.m_iter == b.m_iter && a.m_member == a.m_member; } template< class IterT, class ObjT, class MemberT > inline bool operator!=( const slicing_iterator<IterT,ObjT,MemberT>& a, const slicing_iterator<IterT,ObjT,MemberT>& b ) { return a.m_iter != b.m_iter || a.m_member != a.m_member; } template< class IterT, class ObjT, class MemberT > inline slicing_iterator<IterT,ObjT,MemberT> make_slicing_iterator( IterT iter, MemberT ObjT::*member ) { return slicing_iterator<IterT,ObjT,MemberT>( iter, member ); } struct S { int i; char *s; float f; }; int main(void) { std::vector<S> v(10); std::min_element( make_slicing_iterator(v.begin(), &S::f), make_slicing_iterator(v.end(), &S::f) ); return 0; } 

At first I didn’t notice - it looks like what @Stuart Golodetz suggested, but the advantage is that the <operator does not need to be defined for the type of iterator (for example, std :: list :: iterator). This makes the implementation universal.

+2
source

All Articles