2017-02-01 9 views
0

私は、Sieve of 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; 
} 

しかし、範囲ベースのループは読み、演算子*を使用することを防ぐことが容易であるので、私は代わりにそれを使用したいと思う

ので、私の質問です:範囲ベースのループを別の演算子を使用するようにする方法はあります=(この場合は<)?おそらくprimes_rangeの特定の関数をオーバーライドしたり、コンパレータを特化したりしますか?

+0

いいえ。範囲ベースループの意味はそのまま定義されており、カスタマイズすることはできません。唯一のカスタマイズポイントは、開始値と終了値です。 –

+0

'primes_range'を再設計する必要があります。 'prime_generator'を返す代わりに、それはラッパーを返すべきです。 –

+0

T.C. ? – Steranoid

答えて

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++を介して「次の取得」オペレーションをサポートするが、例えば索引付けによるランダムアクセスはサポートしないものである。イテレータで使用する最適なアルゴリズムについての標準的なライブラリメソッドをヒントするために、このカテゴリフィールドをイテレータクラスで宣言することをお勧めします。
+0

これはすでにそうです。すべての作業を行うendメソッドについては、end()メソッドはprime_generatorをインクリメントして最終素数を取得します(primes_range(10).end 2でジェネレータを作成してから3,5,7、そして最後に11にして11を返す)ので、範囲ベースのループを使用すると同じループを2回使用します。 – Steranoid

+0

ふるいの仕方は覚えていませんが、素数を生成するには0または1から始める必要があると思います。正しいですか?これが当てはまる場合は、 'curr = 1'を使ってイテレータを作成しなければなりません'end()'メソッドの比較のためだけに無効なイテレータを使用しています。なぜなら、あなたはすぐに最後の素数を生成することができないからです。私は完全な例でもう一度答えを書くつもりだと思う。 –

+1

いいえ、2から始まります。 1は素数でも0でもありません。 – Steranoid

0

ここではイテレータの完全な例を示します。上記のことを忘れたのは、現在のイテレータとend()メソッドの結果を比較する必要があるため、range based forが動作するためにはoperator!=が必要です。以下のコードでは、アルゴリズムの正しい実装をgenerate_next_prime関数に置くか、必要に応じてキャッサ内に配置するだけです。

#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; 
} 
+1

'cur'を' limit'で囲む必要があります。 ( 'cur'はプライムで限界を越えるかもしれないので)。 – Jarod42

+0

はい@ Jarod42、そうです、私は更新します。 –

+0

**編集**以前の**回答**。 1つの質問の2つの答えはありません!それらの1つを削除する –

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); 
    } 
}; 
関連する問題