2012-01-12 4 views
8

私はこのコンテナを持っている:次のコードはうまくコンパイル、ということを考えるとconst_iteratorのみをサポートするコンテナでBOOST_FOREACHを使用するにはどうすればよいですか?

class /*final*/ Row 
{ 
public: 
    typedef FieldIterator const_iterator; 
    typedef FieldIterator iterator; 
    FieldIterator begin() const; 
    FieldIterator end() const; 
    FieldIterator begin(); 
    FieldIterator end(); 
    ... 
}; 

BOOST_FOREACH(Field field, row) 
{ 
} 

しかし、クラスが変更可能なイテレータを持つべきではないので、私は行のクラスを変更し、

class /*final*/ Row 
{ 
public: 
    typedef FieldIterator const_iterator; 
    FieldIterator begin() const; 
    FieldIterator end() const; 
    ... 
}; 

しかし、今と同じforeachループがコンパイルに失敗します:

012変更可能なアクセスを除去することにより、私は BOOST_FOREACHしようとは明らかに失敗した range_mutable_iteratorタイプを、インスタンス化することを理解し、エラーメッセージから
1>o:\c\boost_1_48_0\boost\foreach.hpp(364): error C2039: 'type' : is not a member of 'boost::mpl::eval_if<C,F1,F2>' 
1>   with 
1>   [ 
1>    C=boost::mpl::false_, 
1>    F1=boost::range_const_iterator<sqlserver::Row>, 
1>    F2=boost::range_mutable_iterator<sqlserver::Row> 
1>   ] 
1>   c:\dev\internal\playmssqlce\playmssqlce.cpp(29) : see reference to class template instantiation 'boost::foreach_detail_::foreach_iterator<T,C>' being compiled 
1>   with 
1>   [ 
1>    T=sqlserver::Row, 
1>    C=boost::mpl::false_ 
1>   ] 
... 

。代わりに定数範囲をインスタンス化するにはどうすればよいですか?

ありがとうございました。ここで

EDIT

はとのための完全なクラス宣言です:

class /*final*/ Row 
{ 
    const BYTE *m_buffer; 
    const DBBINDING *m_pColumnBindings; 
    int m_columnBindingCount; 
    FieldIterator m_end; 
public: 
    typedef FieldIterator const_iterator; 
    typedef FieldIterator iterator; 
    Row(const BYTE *buffer, const DBBINDING *pColumnBindings, int columnBindingCount); 
    bool isSameRow(const Row& r) const; 
    int fieldCount() const; 
    Field field(int i) const; 
    Field& field(int i, void *fieldBuffer) const; 
    FieldIterator begin() const; 
    FieldIterator end() const; 
    FieldIterator begin(); 
    FieldIterator end(); 
}; 

class FieldIterator : public iterator_facade<FieldIterator, Field, boost::random_access_traversal_tag> 
{ 
    const Row *m_pRow; 
    int m_index; 
    mutable BYTE m_fieldBuffer[sizeof(Field)]; 
public: 
    FieldIterator(const Row *pRow = NULL, int index = 0); 
private: 
    friend class boost::iterator_core_access; 
    void increment(); 
    void decrement(); 
    void advance(difference_type n); 
    difference_type distance_to(FieldIterator it); 
    reference dereference() const; 
    bool equal(const FieldIterator& rhs) const; 
}; 
+1

'BOOST_FOREACH(constフィールドとフィールドの行)'は機能しますか? – Ferruccio

+0

正確に同じ結果です。 – mark

答えて

6

回避策実際にiteratorメンバーが反復子のペアを使用しないようにしたい場合は、ブースト1.52で

BOOST_FOREACH(Field field, std::make_pair(row.begin(), row.end())) 
+0

OKです。唯一の問題は、少し冗長すぎるが、マクロでは修正できないことではないということです。 – mark

0

はCONSTと非const反復子メソッドの同じイテレータ・クラスのように見えます。 BOOST_FOREACHは、Cスタイルの配列を含む任意のコンテナで動作し、問題がクラスにあると考えることができます。あなたはそれのためのコードを投稿できますか?

+0

完了 - 質問の本文の変更を確認します。 – mark

5

元のコードで何が間違っていましたか?

std::setstd::multisetのような標準ライブラリコンテナの中には、すべてconst(更新不可)のイテレータがあります。標準は、具体的に言う: 値型は、キータイプは、両方のイテレータとconst_iteratorのと同じである連想コンテナの

が一定イテレータです。 iteratorとconst_iteratorが同じ型であるかどうかは不明です。 です。

あなたはおそらく、あなたのクラスで

typedef const_iterator iterator; 

で逃げるでしょう。

+0

私のコンテナは、連想されたものではありません。したがって、この節は私のコードには当てはまりません。 – mark

+0

独自のコンテナを定義する場合は、必要に応じて定義することができます。標準コンテナの中には、要素に対する読み取り専用アクセスしか持たないイテレータがあることを指摘したいと思います。推測*彼らはブーストと一緒に働く! –

+0

私は、 'begin()'と 'end()'メソッドの可変バージョンを定義したくありません。あなたのアドバイスは合法ですが、可能であれば可変APIを完全に削除することは、const APIに短絡するよりも優れています。 – mark

0

(私は他のバージョンでテストしていません)、BOOST_FOREACH(Field field, const_cast<Row const&>(row))はあまりにも動作します。