基于范围的循环使用另一个运算符

时间:2017-02-01 10:56:30

标签: c++ c++11

我有一个基于我在Eratosthenes筛选中在python中看到的主要生成器,所以这个生成器基本上生成具有良好性能的素数。

我想要的是在一系列素数上使用基于范围的循环,所以这就是我所做的:

//Consider prime_generator a class with both operator*, operator!= and operator< overloaded

class primes_range {
private:
    unsigned int max;
public:
    primes_range(unsigned int max) : max(max) {}
    prime_generator begin() const {
        return prime_generator(); //so this generator begin from 2 to
                                  //infinity and beyond but of course
                                  //all primes
    }
    prime_generator end() const {
         prime_generator result;
         for (:*result < max; ++result) {} //so this thing actually create a 
                                           //generator and increment it until it
                                           //gives the first prime number 
                                           //above max so it basically do
                                           //all the work that I don't
                                           //want it to do now
         return rest;
    }
};

所以在我的主要内容中,我想使用基于范围的循环,这是primes_range类的重点。

int main() {
    for (auto && i : primes_range(10)) { //So here, this is silly because
                                         //the range-based loop will use end()
                                         //wich will calculate all the prime
                                         //numbers at the very beginning
                                         //and i will increment apart from
                                         //this starting process
        cout << i << endl;
    }
    return 0;
}

当然,我可以使用一个简单的循环:

int main() {
    for (prime_generator pg; *pg < 10; ++pg) {
        cout << *pg << endl;
    }
    return 0;
}

但是因为基于范围的循环更容易阅读并且阻止使用运算符*,所以我想要使用它,所以我的问题是:是否有办法使基于范围的循环使用另一个运算符而不是!=(在这种情况下&lt;)?也许overloard primes_range的特定函数或专门化比较器?

3 个答案:

答案 0 :(得分:2)

除了在end()方法上完成整个工作之外,迭代器必须在每次调用operator++时生成下一个素数,然后在调用operator*时返回它们。因此,迭代器类的方案可能是:

class prime_generator {
   typedef std::forward_iterator_tag iterator_category;
   int cur;
   prime_generator& operator++() {
      cur = GenerateNextPrime();
      return *this;
   }
   int operator*() {
      return curr;
   }
};

注意:

  • 对于基于范围的工作,您的迭代器类至少需要operator++operator*,上面有签名。
  • 迭代器类中声明的forward_iterator_tag告诉你要创建什么类型的迭代器。在这种情况下,前向迭代器是通过operator++支持“获取下一个”操作但不通过索引进行随机访问的操作。在迭代器类中声明此类别字段是一种很好的做法,以便提示有关与迭代器一起使用的最佳算法的标准库方法。

答案 1 :(得分:0)

以下是迭代器的完整示例。我忘记在上面提到operator!=需要range based for才能工作,因为它必须将当前迭代器与end()方法的结果进行比较。在下面的代码中,您只需将算法的正确实现放在generate_next_prime函数中,或者根据需要将其放在casses中。

#include <iostream>
#include <iterator>

int generate_next_prime(int previous) {
    // TODO: a correct one!
    return previous + 1;
}

class prime_generator {
    int limit;

public:

    prime_generator(int limit)
        : limit(limit) {}

    class iterator {
        int cur, limit;

    public:

        typedef std::forward_iterator_tag iterator_category;

        iterator(int cur, int limit)
            : cur(cur), limit(limit) {}

        iterator& operator++() {
            cur = generate_next_prime(cur);
            return *this;
        }   

        bool operator==(const iterator &other) {
            // NOTE: for the primes application maybe you should
            // use >= instead of == to ensure cur will not pass limit
            // silently, or do something more elaborate
            return cur == other.cur &&
                   limit == other.limit;
        }

        bool operator!=(const iterator &other) {
            return !(*this == other);
        }   

        int operator*() {
            return cur;
        }   
    };  

    iterator begin() {
        return iterator(2, limit);
    }

    iterator end() {
        return iterator(limit, limit);
    }
};

int main() {
    for (auto p : prime_generator(5))
        std::cout << p << std::endl;

    return 0;
}

答案 2 :(得分:0)

根据你告诉我的内容,我来这里是一个解决方案,这基本上是一个适配器。

class primes_range {
private:
    unsigned int max;

    class limited_prime_generator {
    private:
        prime_generator pg;
        unsigned int limit;
        bool reachedLimit;

    public:
        limited_prime_generator(unsigned int limit, bool reachedLimit = false) : pg(), limit(limit), reachedLimit(reachedLimit) {}

        limited_prime_generator & operator++() {
            if (not reachedLimit) {
                reachedLimit = *(++pg) >= limit;
            }

            return *this;
        }
        bool operator!=(limited_prime_generator const & lpg) const {
            return operator*() != *lpg;
        }
        unsigned int operator*() const {
            if (reachedLimit)
                return limit;
            else
                return *pg;
        }
    };

public:
    primes_range(unsigned int max) : max(max) {}

    limited_prime_generator begin() const {
        return limited_prime_generator(max);
    }

    limited_prime_generator end() const {
        return limited_prime_generator(max, true);
    }
};