Come posso utilizzare BOOST_FOREACH con un contenitore che supporta solo const_iterator?
-
27-10-2019 - |
Domanda
Ho questo contenitore:
class /*final*/ Row
{
public:
typedef FieldIterator const_iterator;
typedef FieldIterator iterator;
FieldIterator begin() const;
FieldIterator end() const;
FieldIterator begin();
FieldIterator end();
...
};
Detto questo, il seguente codice viene compilato perfettamente:
BOOST_FOREACH(Field field, row)
{
}
comunque, il Row
la classe non dovrebbe avere l'iteratore mutabile, quindi ho cambiato la classe Row rimuovendo l'accesso mutabile:
class /*final*/ Row
{
public:
typedef FieldIterator const_iterator;
FieldIterator begin() const;
FieldIterator end() const;
...
};
Ma ora lo stesso ciclo foreach non riesce a compilare:
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> ]
...
Dal messaggio di errore lo capisco BOOST_FOREACH
cerca di istanziare a range_mutable_iterator
tipo, che ovviamente fallisce.Come posso invece creare un'istanza dell'intervallo costante?
Grazie.
MODIFICARE
Ecco le dichiarazioni di classe complete per Row
E FieldIterator
:
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;
};
Soluzione
UN lavoro Se vuoi davvero evitare il iterator
Il membro deve usare una coppia di iteratori.
BOOST_FOREACH(Field field, std::make_pair(row.begin(), row.end()))
Altri suggerimenti
Cosa c'era di sbagliato nel tuo codice originale?
Alcuni dei contenitori della libreria standard, come std::set
E std::multiset
, hanno iteratori tutti const (nessun aggiornamento consentito).La norma specificatamente dice:
Per i contenitori associativi in cui il tipo di valore è uguale al tipo chiave, sia iteratore che const_iterator sono iteratori costanti.Non è specificato se iteratore e const_iterator siano o meno lo stesso tipo.
Probabilmente te la caveresti
typedef const_iterator iterator;
nella tua classe.
FieldIterator
Sembra essere la stessa classe di iterator per i metodi ITERATOR CONST e non consolati. BOOST_FOREACH
Funziona con qualsiasi contenitore, inclusi array in stile C che mi porta a pensare che il problema sia nel FieldIterator
classe. Puoi pubblicare il codice per questo?
Con Boost 1.52 (non ho testato con altre versioni), BOOST_FOREACH(Field field, const_cast<Row const&>(row))
funzionerà anche tu.