【问题标题】:From integer-indexed for loop enumeration to range-for从整数索引的 for 循环枚举到 range-for
【发布时间】:2016-09-14 19:17:22
【问题描述】:

我有一些代码可以枚举一些数据,如下所示:

int count;
InitDataEnumeration(/* some init params */, &count);

for (int i = 0; i < count; i++) 
{ 
    EnumGetData(i, &data);
    // process data ...
}

我想将此代码转换为适合 C++11 的 range-for 的形式。

我正在考虑定义一个DataEnumerator 包装类,其构造函数将调用上述InitDataEnumeration() 函数。

我们的想法是像这样使用这个包装类:

DataEnumerator enumerator{/* init params*/};

for (const auto& data : enumerator) 
{
    // process data ...
}

如何将前一个int-indexed for 循环重构为后一个基于范围的形式?

我正在考虑从枚举器包装类中公开begin()end() 方法,但我不知道它们应该返回什么样的迭代器,以及如何定义这样的迭代器。

注意迭代过程是只进的。

【问题讨论】:

  • 我看不到“重复”链接问题中对我的问题的回答。

标签: c++ c++11 iterator


【解决方案1】:

您可以使用boost::irange 完成您要查找的内容。它将在 [first, last) 范围内构造一个惰性整数范围,您可以像在 for 循环中使用 i 一样将其直接放入。

for (int i = 0; i < count; i++) 
{ 
    EnumGetData(i, &data);
    // process data ...
}

变成

for (auto i : boost::irange(0, count))
{
    EnumGetData(i, &data);
    // process data ...
}

【讨论】:

  • 对不起,但这并没有为索引添加任何好处。请查看我的第二个代码 sn-p 以了解所需的代码。
【解决方案2】:

您需要一个输入迭代器,此示例完全从 http://en.cppreference.com/w/cpp/iterator/iterator 复制而来:

#include <iostream>
#include <algorithm>

template<long FROM, long TO>
class Range {
public:
    // member typedefs provided through inheriting from std::iterator
    class iterator: public std::iterator<
                    std::input_iterator_tag,   // iterator_category
                    long,                      // value_type
                    long,                      // difference_type
                    const long*,               // pointer
                    long                       // reference
                                  >{
    long num = FROM;
    public:
    explicit iterator(long _num = 0) : num(_num) {}
    iterator& operator++() {num = TO >= FROM ? num + 1: num - 1; return *this;}
    iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
    bool operator==(iterator other) const {return num == other.num;}
    bool operator!=(iterator other) const {return !(*this == other);}
    reference operator*() const {return num;}
    };
    iterator begin() {return iterator(FROM);}
    iterator end() {return iterator(TO >= FROM? TO+1 : TO-1);}
};

int main() {
    // std::find requires a input iterator
    auto range = Range<15, 25>();
    auto itr = std::find(range.begin(), range.end(), 18);
    std::cout << *itr << '\n'; // 18

    // Range::iterator also satisfies range-based for requirements
    for(long l : Range<3, 5>()) {
    std::cout << l << ' '; // 3 4 5
    }
    std::cout << '\n';
}

【讨论】:

  • 我回滚了编辑以添加引号,因为这是复制材料,应该这样标记
  • 另请注意,这是一个模板,因此它仅在编译时知道大小时才有效。如果它依赖于运行时间,这将不起作用。
【解决方案3】:

您对begin()end() 的看法是正确的,无论它们返回什么都应该提供:

  • operator++(前缀就够了)
  • 接线员!=
  • 操作员*

一切都非常不言自明。

请注意,不需要特征或类别,就像用于某些标准库算法的迭代器一样 - 只是最低要求。

【讨论】:

    【解决方案4】:

    for(auto x : y) 这里,y 必须是具有begin() 方法和end() 方法的类的对象,每个方法都返回一个实现迭代器概念的对象。迭代器必须是可递增的 (iter++),必须能够准确地确定它是否等于另一个同类迭代器(通过 !=),并且必须取消对 x 的引用。

    如果您 A) 感到无聊或没有更好的事情可做或 B) 有正当需要,那么您应该考虑这样做。虽然这并不难做到,但也不是微不足道的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-26
      • 1970-01-01
      • 2015-12-13
      • 2021-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-07
      相关资源
      最近更新 更多