Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterator "pointing" to a member of an object

Tags:

c++

iterator

stl

I admit I had difficulties coming up with a reasonable description for this. I cannot think of a good term that would describe precisely what I'm looking for. Perhaps this could be called a slicing 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 construct an iterator, that would point to a member of S. I'd like to be able 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 that I could use to achieve this? Or perhaps it's already done somewhere in Boost or some other library?

like image 570
detunized Avatar asked Apr 29 '11 10:04

detunized


3 Answers

If you're looking for an iterator that converts S into its S::f, this could certainly be done using boost (what 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're looking for the S whose S::f is the smallest in the vector, the predicate is the most reasonable approach.

like image 86
Cubbi Avatar answered Oct 11 '22 23:10

Cubbi


If you don't want to create a predicate function for each case, I would suggest not to look for a slicing operator, but to implement your predicate as a lambda function (either using Boost or C++0x). Here you will find a detailed explanation

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

(this is about std::sort, but the comparison in std::min_element works equally.)

like image 45
Doc Brown Avatar answered Oct 12 '22 01:10

Doc Brown


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;
    M T::*m_m;
public:
    SlicingIterator(const Iterator& it, M T::*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, M T::*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;
}
like image 42
Stuart Golodetz Avatar answered Oct 12 '22 00:10

Stuart Golodetz