Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

iterator

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

like image 379
Ogunleye Ayowale Pius Avatar asked Nov 02 '18 08:11

Ogunleye Ayowale Pius


1 Answers

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).

like image 105
Max Langhof Avatar answered Oct 14 '22 03:10

Max Langhof