简体   繁体   中英

How to wrap std::chrono in a c++ iterator type

I am try to create an iterable type which receives a template argument of a specific duration type, say std::seconds , std::hours , etc., and I want it to receive as argument 2 values that represent time_points of the specified duration, and be able to use such a construct in a range based for loop by increasing the current time_point by a unit of that duration or maybe of a specified duration, something like the following:

DateRange<std::seconds> dr(now() , 50);
for(auto d : dr){
 // do something at unit time
}

I have tried to implement it this way

   using namespace std::chrono;
   template<typename Duration , typename Clock_t = high_resolution_clock, 
   typename Time_type = time_point<Clock_t, typename Duration> , typename 
   Time_pointer = Time_type* >
 class DateRange {
   using Time_type_t = typename Time_type::duration;
 public:
   DateRange(Time_type_t start, Time_type_t end) :
    m_begin(start),
    m_end(end)
   {

   }
   DateRange(Time_type_t end):
    m_begin(Clock_t::now())

   {

   }
   Time_pointer begin(){
    return &m_begin;
   }
   Time_pointer end() {
    return &m_end;
    }

    Time_pointer operator++(){
    present +=Duration(1);
    return present_point;
   }

 Time_type operator*(){
    return present;
  }

private:
Time_type m_begin;
Time_type m_end;
Time_type present;
Time_pointer present_point = &present;
Clock_t l_clock;
};
int main()
{
DateRange<seconds> dr(40s);
dr.operator++();
    std::cout << (*dr).time_since_epoch().count();
 }

'std::chrono::time_point::time_point(std::chrono::time_point &&)': cannot convert argument 1 from 'std::chrono::steady_clock::time_point' to 'const _Duration &' DateRange at line 19

Range-based for loops ( for ( range_declaration : range_expression ) loop_statement ) are syntactic sugar for (in your case) this :

{
    auto && __range = range_expression ;
    auto __begin = __range.begin();
    auto __end = __range.end();
    for ( ; __begin != __end; ++__begin)
    {
        range_declaration = *__begin;
        loop_statement
    }
} 

Without concerning ourselves with the finer details of this (or how it changed throughout C++ versions), this explains why your code currently cannot work. You are attempting to do this:

  • auto && __range = myDateRange; - Ok, our range is a DateRange . This is fine.

  • auto __begin = __range.begin();
    auto __end = __range.end();
    So __begin and __end are now Time_type* ... This is already looking bad.

  • Now the loop will increment __begin , but it is a TimeType* that does not point into an array. Dereferencing the incremented __begin (as done in the next statement) will thus be Undefined Behavior. Note how operator++ of the range_expression is never called.

Regardless of if you fix the compiler error (and missing initialization in DateRange(Time_type_t end) ), this approach will not work. You need an iterator class that keeps a reference to your DateRange . This iterator is returned by begin() and end() and has itself an operator++() and operator*() (which would return an appropriate time_point ).

The value you return from begin needs to eventually be equal to the value you return from end by some amount of ++ . Currently whether this is possible is unspecified, as you return pointers to distinct objects.

You probably need a separate iterator type.

template<typename Duration, typename Clock = high_resolution_clock>
class DateRange {
   using Time_type = time_point<Clock, Duration>;

   class iterator {
     iterator & operator++(){
       present += Duration(1);
       return *this;
     }

     iterator operator++(int){
       iterator res = *this;
       ++res;
       return res;
     }

     Time_type * operator->(){
       return &present;
     }

     Time_type operator*(){
       return present;
     }

     Time_type present;
   };

   Time_type m_begin;
   Time_type m_end;
public:
  DateRange(Time_type_t start, Time_type_t end) :
    m_begin(start),
    m_end(end)
    {}
  DateRange(Time_type_t end) :
    m_begin(Clock::now()),
    m_end(end)
    {}
  iterator begin(){
    return m_begin;
  }
  iterator end() {
    return m_end;
  }
};

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