2011-12-28 3 views
2
int main() { 
    boost::regex reg("(\\d+),?"); 
    std::string s="1,1,2,3,5,8,13,21"; 

    boost::sregex_iterator it(s.begin(),s.end(),reg); 
    boost::sregex_iterator end; 

    regex_callback c; 
    int sum=for_each(it,end,c).sum(); 
} 

あなたが見ることができるように、for_eachに渡された過去エンドイテレータは単に regex_iteratorのデフォルト・構築インスタンスです。デフォルトの構築されたイテレータをワンパスエンドランドマークに使用できるのはなぜですか?

質問>endがどのコンテナに関連付けられていないため、どのようstd::for_eachは、コンテナのONE-PASS-ENDのランドマークとして使用することができませんか?

はあなたに

答えて

2

まあありがとう、regex_iterator()の説明は次のとおりです。

regex_iterator(); 
Effects: constructs an end of sequence regex_iterator. 

)(次の仮想的な疑似codey定義に次のようにこれが起こる可能性:また

void boost::regex_iterator::next() { 
    this->ptr++; 
    if (this->ptr == this->original_defined_end_ptr) { 
     this = regex_iterator(); 
    } else { 
     ... 
    } 
} 

class regex_iterator: 
    regex_iterator(): 
     this->only_true_when_compared_to_end_iterator = true 

    regex_iterator(begin, end): 
     this->only_true_when_compared_to_end_iterator = false 
     this->cur = begin 
     this->end = end 

    operator==(other): 
     if this->only_true_when_compared_to_end_iterator: 
      return other->cur == other->end 
     if other->only_true_when_compared_to_end_iterator: 
      return this->cur == this->end 
     return this->cur == other->cur 

    next(): 
     this->cur++ 

それとも:

class regex_iterator: 
    regex_iterator(): 
     this->cur = 0 

    regex_iterator(begin, end): 
     this->cur = begin 
     this->end = end 

    operator==(other): 
     return this->cur == other->cur 

    next(): 
     this->cur = this->cur->next() 
     if this->cur == this->end: 
      this->cur = 0 
+0

私はまだ、さまざまなコンテナで動作するエンドイテレータを設計する方法を理解できません。 – q0987

+0

あなたの例に基づいて、どのように我々は、異なるメモリ空間を占有異なるコンテナそれぞれの間で同じ 'original_defined_end_ptr'を共有することができます。 – q0987

+0

私はq0987 @ –

2

それは非常に簡単です。反復子itは、ある時点で反復子endと等しくなるように増分します。いつそれはendと等しくなりますか?イテレータitがそれ以上繰り返すことができるアイテムがなくなったとき。

クラスboost::sregex_iteratorはデフォルト構築イテレータendが作成されると、どのような価値は、それがit同じ価値を与えることができますので、持つ、またはoperator!=の実装はイテレータと推論の場合を比較するために使用するいくつかの値がされた方法を知っているので、彼らは不平等であるかどうか。つまり、イテレータを比較するoperator!=の定義にも依存します。

は、例えばとして、このrange_iteratorは、基本的な考え方を示すために参照してください。

struct range_iterator 
{ 
     int lower_, upper_; 
     range_iterator() : upper_(0), lower_(0) 
     {} 
     range_iterator(int lower, int upper) : upper_(upper), lower_(lower) 
     {} 
     int operator*(){ return lower_; } 
     int operator++(){ lower_++; } 

     bool operator != (range_iterator const & other) 
     { 
      return (upper_-lower_) != (other.upper_-other.lower_); 
     } 
}; 

int main() 
{ 
     range_iterator begin(10,25), end; 
     while(begin != end) 
     { 
      std::cout << *begin << std::endl;; 
      ++begin; 
     } 
} 

出力:

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 

オンラインデモ:http://ideone.com/SOzXe

operator!=の実装およびデフォルトを参照してください。コンストラクタ;どのように連動しているのか、そしてイテレータが不等であるかどうかをoperator!=が推論する方法。非常に単純な実装です。私は、このクラスがさまざまな方法で実装できることを知っています。しかしイテレータの平等と不等式の基本的な考え方は同じです。

+0

重要なポイントは、異なるコンテナ間でイテレータをどのように共有するかということです。 – q0987

+0

@ q0987:容器が違うということは、 'type'が違うことを意味しますか?いいえ、異なるタイプ間で共有することはできません。 – Nawaz

+0

同じコンテナタイプの異なるインスタンスを意味します。異なるインスタンスは異なるメモリ空間を使用するため、異なるインスタンス間で共有エンドをどのように使用できるか想像するのは難しいです。 – q0987

4

重要なことは、これはではなく、の一般的な動作です。 標準のデフォルト構築イテレータは、“エンド” iostreamイテレータのイテレータとして動作しますが、イテレータは コンテナにはありません。通常、このイディオムは、入力イテレータ、または が実際にそれを読む前にシーケンスの終わりを知ることが不可能な他の の場合に使用されます。 boost::regexの著者は、boost::sregex_iteratorについては この慣習に従うことにしました。彼らがそうするために確かに 要件はなかった。しかし、それは前方の イテレーターですが、最後までどこにいるのか知ることは一般的に不可能です。 これまで進めようとするので、合理的であるようです。入力イテレータの場合

、“の定義は、” に等しくなく緩んで、約必要とされる全ては、“端としてイテレータ 定義は、”が が“端として定義されていないイテレータに不等を比較することです”;簡単myIsAtEnd部材としてフラグ、及び

bool 
IteratorType::operator==(IteratorType const& other) const 
{ 
    return myIsAtEnd != other.myIsAtEnd; 
} 

又は

bool 
IteratorType::operator==(IteratorType const& other) const 
{ 
    return myIsAtEnd && other.myIsAtEnd; 
} 

はおそらく十分です。 boost::sregex_iteratorは転送先の イテレータであり、単純に入力イテレータではないので、制約は幾分厳密には ですが、上記を包含するように簡単にすることができます。

bool 
boost::sregex_iterator::operator==(
    boost::sregex_iterator const& other) 
{ 
    return myIsAtEnd 
     ? other.myIsAtEnd 
     : (!other.myIsAtEnd 
      && myMatchPosition == other.myMatchPosition); 
} 

デフォルトコンストラクタは、単にtrueにmyIsAtEndを敷石:次のような なもので。 (あなたが使用する他の コンストラクタ最初のマッチを見つけることを試みることによって開始し、 は体系的には一致するものが見つかるかどうかにmyIsAtEndを設定します。)

それはおそらくブーストがしばしば イテレータでこれを行うことを指摘する価値があります。標準イテレータのコンセプトは多かれ少なかれ壊れています( は1つではなく2つのオブジェクトを必要とします)。これは、それを回避するための多かれ少なかれ 標準イディオムです。フィルタリングイテレータのようなものについては、 boost::iteratorで広く使用されています。

1

質問>端は任意のコンテナに関連付けられていないため、どのようにのstd :: for_eachは、コンテナのONE-PASS-ENDのランドマークとして使用することができませんか?

イテレータは、コンテナとまったく関連付ける必要はありません。 1つの例は、コンソール(おそらくキーボード)のような、あるソースから入力を読み込むストリームイテレータです。

このようなイテレータには、次の入力のソースへのポインタが含まれることがあります。入力の終わりに達したら(何とか)、このポインタをNULLに設定することができます。デフォルトの構築済みiteratorにもNULLポインタが含まれていると、終了イテレータのように見えます。

std::for_eachこれについては何も知る必要はありません。それはイテレータ型のためにオーバーロードされたoperator!=を呼び出します。オペレータは、比較される2つのイテレータが両方ともイテレータであるか否かを知る。

関連する問題