【问题标题】:How to wrap std::chrono in a c++ iterator type如何将 std::chrono 包装在 C++ 迭代器类型中
【发布时间】:2018-11-02 08:54:35
【问题描述】:

我正在尝试创建一个可迭代类型,它接收特定持续时间类型的模板参数,例如 std::secondsstd::hours 等,我希望它接收代表 time_points 的参数 2 值指定的持续时间,并能够通过将当前time_point 增加该持续时间的单位或指定的持续时间来在基于范围的 for 循环中使用此类构造,如下所示:

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

我尝试过这样实现

   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 &&)': 无法将参数 1 从 'std::chrono::steady_clock::time_point' 转换为 'const _Duration &' DateRange在第 19 行

【问题讨论】:

  • 你的问题是什么?
  • 考虑将此问题迁移到Code Review
  • 您似乎试图在同一个类中定义一个范围(开始和结束)和一个迭代器(运算符 ++ 和 *),这充其量是令人困惑的
  • a range-based for loop 得到 beginend iteratorsrange 表达式dr案子)。这两种行为理论上可以在同一个类中定义,但这不是它的意图
  • @kmdreko FWIW, fs::directory_iterator 做了类似的事情。所以这并不少见。

标签: c++ iterator


【解决方案1】:

基于范围的 for 循环 (for ( range_declaration : range_expression ) loop_statement) 是(在您的情况下)this 的语法糖:

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

不用关心这个细节(或者它在整个 C++ 版本中是如何变化的),这解释了为什么你的代码目前不能工作。您正在尝试这样做:

  • auto &amp;&amp; __range = myDateRange; - 好的,我们的范围是DateRange。这很好。

  • auto __begin = __range.begin();
    auto __end = __range.end();
    所以__begin__end 现在是Time_type*...这看起来已经很糟糕了。

  • 现在循环将增加__begin,但它是一个不指向数组的TimeType*。因此,取消引用递增的__begin(如在下一条语句中所做的)将是未定义的行为。注意range_expression 中的operator++ 是如何被调用的。

无论您是否修复了编译器错误(以及在DateRange(Time_type_t end) 中缺少初始化),这种方法都不起作用。您需要一个迭代器类来保留对您的DateRange 的引用。此迭代器由begin()end() 返回,并且自身 具有operator++()operator*()(将返回适当的time_point)。

【讨论】:

    【解决方案2】:

    您从begin 返回的值最终需要等于您从end 返回的值,相差一些++。目前这是否可能是未指定的,因为您返回指向不同对象的指针。

    您可能需要一个单独的 iterator 类型。

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

    【讨论】:

    • 技术上很可能单个 ++ 使指针比较相等 - 毕竟它们是相邻的成员。并不是说这是预期的行为。
    • @MaxLanghof 它们不是指向同一个数组的指针,因此不在==的域之外
    • 那是only needed for relational operators。我并不是说它保证没有 UB(如果Time_type 是例如char[3],则填充理论上可以解决这个问题),但是该程序在检查Time_type 指针的相等性方面并不是错误的,是否相同的数组。
    • @MaxLanghof [expr.eq]/3.1 "如果一个指针表示一个完整对象的地址,而另一个指针表示另一个完整对象的最后一个元素之后的地址,则比较的结果是未指定的。 "
    • @OgunleyeAyowalePius “我认为迭代器从根本上说是指针” 你倒退了。所有的指针都是迭代器(虽然很多不是有用的)。并非所有迭代器都是指针。例如。 std::istream_iterator 是一个类模板
    猜你喜欢
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多