2012-04-14 30 views
3

C++で簡単な数値範囲クラスを作成しようとしています。それはあなたが(/ Pythonのarange numpyのように)等間隔のダブルスを反復させます:内部でstd :: vectorやstd :: listを使わないC++ std :: iterator

私がやりたい(ただし、イテレータを)したいもの:

double lower = ..., upper = ..., delta = ...; 
for (double val = lower; val < upper; val += delta) 
{ 
    // do something with val 
    f(val); 
} 
// include the last val to guarantee upper is included or exceeded 
f(val); // do something with val 

希望同等のイテレータコード:

double lower = ..., upper = ..., delta = ...; 
NumericRange nr(lower, upper, delta); 
for (NumericRange::const_iterator iter = nr.begin(); iter != nr.end(); iter++) 
{ 
    f(*iter); 
} 

私は(にNumericRangeを反復することはITERと同等である必要があり、私は、コードを再利用することができますので、私のイテレータはSTLのイテレータと互換性がしたいのですがatdからstd :: vectorまで)。

私はstd :: vector(そしてstd :: vectorのイテレータを使って)に値を格納するだけで成功しました。これは私がオンラインで見つけたすべてがこの問題を解決した方法です。ただし、リスト全体を格納する必要はありません。

値全体を格納しないようにする方法はありますか? std::vector<double>を保存せずに希望の効果を得るには、iterableクラスが継承してから継承できるクラスがありますか?++==などをオーバーライドしますか?

(私は本当にそれは素晴らしいことだにもかかわらず、BOOSTせずにこれを行う方法を知っているように思います。私は)ゼロから(のようなものをの書き方を学びたいと思いますので、私はこれを聞いていますのよBOOSTソリューション私は間違いなく、ソフトウェアエンジニアリングの一部が他の人が作成したツールを使用しているけど、私は実際にそれらのツールを設計・構築されている方法を学びたい)

内部std::vector<double>を使用して私の反復可能にNumericRangeクラス()。。:

class NumericRange 
{ 
protected: 
    double lower, upper, delta; 
    std::vector<double> sorted_range; 
public: 
    typedef std::vector<double>::const_iterator const_iterator; 
    NumericRange() 
    { 
    lower = upper = delta = std::numeric_limits<double>::quiet_NaN(); 
    // vector is constructed empty 
    } 
    NumericRange(double lower_param, double upper_param, double delta_param) 
    { 
    lower = lower_param; 

    upper = upper_param; 
    delta = delta_param; 
    assert(upper_param > lower_param); 

    double val; 
    // note: can be much faster without push_back 
    for (val = lower_param; val < upper_param; val += delta_param) 
     { 
    sorted_range.push_back(val); 
     } 
    // ensure the upper_value is contained or surpassed 
    sorted_range.push_back(val); 
    } 
    // to prevent comparison of the entire vector 
    bool operator ==(const NumericRange & rhs) const 
    { 
    return lower == rhs.lower && upper == rhs.upper && delta == rhs.delta; 
    } 
    // note: this class doesn't really need to store the values in a 
    // vector, but it makes the iterator interface much easier. 
    const_iterator begin() const 
    { 
    return sorted_range.begin(); 
    } 
    const_iterator end() const 
    { 
    return sorted_range.end(); 
    } 
    double get_lower() const 
    { 
    return lower; 
    } 
    double get_upper() const 
    { 
    return upper; 
    } 
    double get_delta() const 
    { 
    return delta; 
    } 
    size_t size() const 
    { 
    return sorted_range.size(); 
    } 
    void print() const 
    { 
    std::cout << "[ " << lower << " : " << upper << ": +=" << delta << " ]" << std::endl; 
    } 
}; 
+0

宗教上の理由から、 –

+1

@MrListerそれは主に冗談として意図されましたが、上記の説明を追加しました。 – user

+0

OK。ねえ、私はライブラリを使うのではなく、自分で何かしたいと思っていることに対して何もしていません。あなたが言ったように、それが「エクササイズ」である限り、ホイールを再発明することさえできます。しかし、その後、あなたは "宗教的理由"を言うようになったので、Boostにいくつかの根本的な問題があるかもしれないと思った。 –

答えて

5

std::vector<double>を保存せずに希望の効果を得るには、++==などから継承して上書きできるクラスがありますか?

はい、あります。その名前はstd::iterator<std::input_iterator_tag, double>です。

ここはあなたのためのスタートで、intを使用しています。私の脳のスペースを節約するために、私は同じクラスを使って範囲とイテレータを表現します。

#include <iterator> 
#include <iostream> 

struct NumericRange : public std::iterator< std::input_iterator_tag, int > 
{ 
    int current, fini, delta; 
    typedef NumericRange iterator; 
    typedef iterator const_iterator; 
    iterator begin() { return *this; } 
    iterator end() { return iterator(fini, fini, delta); } 
    iterator& operator++() { current += delta; return *this; } 
    iterator operator++(int) { iterator result(*this); ++*this; return result; } 
    int operator*() const { return current; } 
    NumericRange(int start, int fini, int delta) 
    : current(start), fini(fini), delta(delta) 
    { 
    } 
    bool operator==(const iterator& rhs) { 
    return rhs.current == current; 
    } 
    bool operator!=(const iterator& rhs) { 
    return !(*this == rhs); 
    } 
}; 

void f(int i, int j) { 
    std::cout << i << " " << j << "\n"; 
} 

int main() { 
    int lower = 4, upper = 14, delta = 5; 
    NumericRange nr(lower, upper, delta); 
    for (NumericRange::const_iterator iter = nr.begin(); iter != nr.end(); iter++) 
    { 
     f(*iter, *nr.end()); 
    } 
} 
+2

素晴らしいです、ありがとうございます。'!='演算子は数値的に危険な直接的な平等のために 'double'を比較するので、' double'ではもう少し難しいです。そうするためには、 'current + = delta'を連続して実行すると、最終的に' current == fini'となることを保証する必要があります。これは、数値エラーのために、 'fini = current + k *(delta)'(kは整数)と必ずしも同じではありません。この理由から、私は数値エラーを拘束し、 '!='を実行するときにこの境界内の近似等価性をテストします。 – user

+0

それで、私は 'int'で始まったのです。二重のバージョンを作ることは、練習として残されています。 –

関連する問題