Boost logo

Boost Users :

Subject: Re: [Boost-users] Iterating over the seconds of a list of pairs
From: Björn Karlsson (Bjorn.Karlsson_at_[hidden])
Date: 2009-08-08 13:12:17


Hello Zach,

> I have an std::list<std::pair<double, float> > internal to a class.
> I'd like to expose begin() and end() functions from this class, that
> iterate over the second element of the list. So basically I want the
> user of the class to only see a sequence of floats.
> transform_iterator seems to fit the bill, but I think I'm seriously
> overcomplicating this. I've tried the following and it's not working.
> I feel like this pair_second / pair_first, and iterator should either
> already all be defined somewhere that I'm just not aware of, or be
> much shorter to write than this.

You're right -- transform_iterator is the right tool for the job. Try something like this.

1) Write a function object that extracts the second element of the pair.
2) Use the transform iterator adaptor to provide you with the type of the iterators for your class.
3) Use the helper function make_transform_iterator in your begin() and end() methods to create the iterators.

Here's an example that does the above:

#include <iostream>
#include <list>
#include <utility>

#include "boost/iterator/transform_iterator.hpp"

// Extract the second element of a pair
template <typename T> class pair_second_t {
public:
  typedef T result_type;

  template <typename U> T operator()(const std::pair<U,T>& element) const
  {
    return element.second;
  }
};

class some_class
{
public:
  typedef std::list<std::pair<double,float> > container_type;
  typedef boost::transform_iterator<pair_second_t<float>,
container_type::iterator> iterator_type;

  some_class()
  {
    // Add some sample elements
    container_.push_back(std::make_pair(2.123, 3.14f));
    container_.push_back(std::make_pair(4.123, 4.14f));
    container_.push_back(std::make_pair(7.123, 5.14f));
    container_.push_back(std::make_pair(8.123, 6.14f));
  }
  
  iterator_type begin()
  {
    return boost::make_transform_iterator(
      container_.begin(),
      pair_second_t<float>());
  }

  iterator_type end()
  {
    return boost::make_transform_iterator(
      container_.end(),
      pair_second_t<float>());
  }
  
private:
  container_type container_;
};

int main(int argc, char* argv[])
{
  some_class sc;

  some_class::iterator_type it, end;
  
  it = sc.begin();
  end = sc.end();

  while (it != end)
  {
    std::cout << *it++ << '\n';
  }

  return 0;
}

Cheers,
Bjorn Karlsson
www.skeletonsoftware.net


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net