Question

I have this container:

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

Given that, the following code compiles just fine:

BOOST_FOREACH(Field field, row)
{
}

However, the Row class should not have the mutable iterator, so I changed the Row class, by removing the mutable access:

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

But now the same foreach loop fails to compile:

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>          ]
...

From the error message I understand that BOOST_FOREACH tries to instantiate a range_mutable_iterator type, which obviously fails. How do I make it to instantiate the constant range instead?

Thanks.

EDIT

Here is the complete class declarations for Row and 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;
};
Was it helpful?

Solution

A work-around if you really want to avoid the iterator member is to use a pair of iterators.

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

OTHER TIPS

What was wrong with your original code?

Some of the standard library containers, like std::set and std::multiset, have iterators that are all const (no update allowed). The standard specifically says:

For associative containers where the value type is the same as the key type, both iterator and const_iterator are constant iterators. It is unspecified whether or not iterator and const_iterator are the same type.

You would probably get away with

typedef const_iterator iterator;

in your class.

FieldIterator appears to be the same iterator class for const and non-const iterator methods. BOOST_FOREACH works with any container including C-style arrays which leads me to think the problem is in the FieldIterator class. Can you post the code for it?

With boost 1.52 (I have not tested with other versions), BOOST_FOREACH(Field field, const_cast<Row const&>(row)) will work too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top