【问题标题】:Traversing boost::month_iterators using ranges使用范围遍历 boost::month_iterators
【发布时间】:2013-04-18 10:39:59
【问题描述】:

我正在尝试用一种惯用的方式来写这篇文章

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;
}

这很好,但我想知道是否有这样的写法

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);
});

相同的结果,但我认为它是更漂亮的代码,它更像是一种函数式方法(我喜欢),而且我想要实现的意图更清晰。 我有一种感觉我必须使用 any_range 但我不确定在这种情况下如何,因为 month_iterator 似乎没有前向迭代器的所有正常语义

【问题讨论】:

    标签: c++ date boost c++11 iterator


    【解决方案1】:

    没有简单的方法可以做到这一点。首先你应该像这样专门化std::iterator_traits

    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;
    };
    
    }
    

    其次,您不能使用任何boost::range,因为两个迭代器没有operator ==,也没有operator * const。所以,你应该编写自己的类,可能派生自boost::iterator_adaptor,但是,我认为,这个迭代器根本不是为这种用途而创建的。

    我在写一个小例子,效果不大,但是很有效,没有过于复杂。

    #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;
    }
    

    【讨论】:

    • 好的,谢谢。遗憾的是 date_time 迭代器没有遵循与其他双向迭代器相同的语义,因为从语义上看它们应该
    猜你喜欢
    • 2010-09-14
    • 1970-01-01
    • 2018-04-07
    • 2017-03-26
    • 1970-01-01
    • 2020-09-07
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多