简体   繁体   中英

Traversing boost::month_iterators using ranges

I'm trying to come up with an idomatic way of writing this

boost::gregorian::month_iterator start(boost::gregorian::date(1901,1,1),1);
boost::gregorian::date end(2000,12,31);
int i = 0;
while(start <= end) {
    boost::gregorian::gregorian_calendar::day_of_week_type x = (*start).day_of_week();
if(x==0)
      ++i;
}

This is fine, but I wondered if there was a way of writing it like

boost::gregorian::month_iterator start(boost::gregorian::date(1901,1,1),1);
boost::gregorian::month_iterator end(boost::gregorian::date(2000,12,31));

const int i = std::count_if(start,end,[](boost::gregorian::month_iterator& start) {
    boost::gregorian::gregorian_calendar::day_of_week_type x = (*start).day_of_week();
    return (x==0);
});

Same result, but I think it's prettier code, it's more like a functional approach (which I like) and the intention of what I'm trying to achieve is clearer. I have a feeling I have to use any_range<> but I'm not really sure how in this case as the month_iterator doesn't seem to have all the normal semantics of forward iterators

There is no simple way to do this. Firstly you should specialize std::iterator_traits for example like this

namespace std {

template<>
struct iterator_traits<boost::gregorian::month_iterator>
{
   typedef ptrdiff_t difference_type;
   typedef boost::gregorian::month_iterator value_type;
   typedef boost::gregorian::month_iterator& reference;
   typedef boost::gregorian::month_iterator* pointer;
};

}

Secondly, you cannot use any boost::range since there is no operator == for two iterators and there is no operator * const . So, you should write your own class, probably derived from boost::iterator_adaptor , however, I think, this iterator is simply not created for such usage.

I'm writing small example, which is not effective, but it works and there is no excessively complexity.

#include <boost/range.hpp>
#include <boost/range/any_range.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/shared_ptr.hpp>

#include <vector>

namespace std {

template<>
struct iterator_traits<boost::gregorian::month_iterator>
{
   typedef ptrdiff_t difference_type;
   typedef boost::gregorian::month_iterator value_type;
   typedef boost::gregorian::month_iterator& reference;
   typedef boost::gregorian::month_iterator* pointer;
};

}

class month_iterator : public boost::iterator_adaptor
<
   month_iterator,
   boost::gregorian::month_iterator*,
   boost::gregorian::month_iterator::value_type,
   boost::bidirectional_traversal_tag,
   boost::gregorian::month_iterator::value_type&
>
{
   friend class boost::iterator_core_access;
public:
   month_iterator() : m_it(boost::gregorian::date(boost::gregorian::not_a_date_time)) {}
   explicit month_iterator(const boost::gregorian::month_iterator& pos) :
      m_it(pos)
   {
      receive_value();
   }
   reference dereference() const
   {
      return *value;
   }
   bool equal(const month_iterator& rhs) const
   {
      return *value >= *rhs.value;
   }
   void increment()
   {
      ++m_it;
      *this = month_iterator(m_it);
   }
private:
   void receive_value()
   {
      value.reset(new value_type(*m_it));
   }
   boost::gregorian::month_iterator m_it;
   boost::shared_ptr<value_type> value;
};

int main()
{
   boost::gregorian::month_iterator start(boost::gregorian::date(1901,1,1),1);
   boost::gregorian::month_iterator end(boost::gregorian::date(2000,12,31));

   month_iterator p(start), e(end);
   const int result = std::count_if(p, e, [](const month_iterator::value_type& v)
   {
      return v.day_of_week() == 0;
   });
   std::cout << result << std::endl;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM