Right now, I have a class that can satisfy an API requirement with a random-access iterator. However, I can envision a situation where the implementation will change and only a forward iterator can be provided.
Therefore, I would like to restrict callers from using the random-access functionality. I know I can write my own implementation (e.g. restricted_bar_iterator), but was wondering if there is anything simpler (i.e. requiring less coding).
class BAR { ... };
class FOO {
public:
// Bad...clients may expect 'bar_iterator' to be random access...
typedef std::vector<BAR>::iterator bar_iterator;
bar_iterator begin_bar() const;
bar_iterator end_bar() const;
// Possible solution here!
class restricted_bar_iterator :
public std::iterator< std::forward_iterator_tag, BAR > { ... };
};
void baz()
{
FOO foo;
bar_iterator it = foo.begin_bar() + 5; // want a compile time error here!
}
Here's an example using Boost Iterator Adaptor. I used int
instead of BAR
.
#include <boost/iterator/iterator_adaptor.hpp>
#include <vector>
struct iterator :
public boost::iterator_adaptor<
iterator, // the name of our class, see docs for details
std::vector<int>::iterator, // underlying base iterator
boost::use_default, // for value type
boost::forward_traversal_tag // all the boilerplate for this!
>
{
// need this to convert from vector::iterator to ours
explicit iterator(std::vector<int>::iterator i)
: iterator::iterator_adaptor_(i) {}
};
int main()
{
std::vector<int> v;
iterator it(v.begin());
++it; // OK
it += 1; // ERROR
}
This effectively uses a std::vector<T>::iterator
as a base class, but only allows operations that are defined for forward iterators. The downside are the error messages - they aren't very pretty.
You definitely have to do some coding, but you might be able to inherit from the underlying type to get most of the functionality, just overriding the operations you don't want to work, either by defining them as deleted in C++11 or making them private and unimplemented in C++03:
class FOO {
// Bad...clients may expect 'bar_iterator' to be random access...
typedef std::vector<BAR>::iterator bar_iterator_impl;
public:
// Possible solution here!
struct bar_iterator : bar_iterator_impl {
bar_iterator& operator++() {
++static_cast<bar_iterator_impl&>(*this);
return *this;
}
bar_iterator operator++(int) {
bar_iterator copy(*this);
++*this;
return copy;
}
typedef std::forward_iterator_tag iterator_category;
typedef std::iterator_traits<bar_iterator_impl>::value_type value_type;
typedef std::iterator_traits<bar_iterator_impl>::difference_type difference_type;
typedef std::iterator_traits<bar_iterator_impl>::pointer pointer;
typedef std::iterator_traits<bar_iterator_impl>::reference reference;
private:
friend void operator+(bar_iterator const&, long);
friend void operator+(long, bar_iterator const&);
friend void operator-(bar_iterator const&, long);
friend void operator-(long, bar_iterator const&);
};
bar_iterator begin_bar() const;
bar_iterator end_bar() const;
};
However this only works if std::vector<BAR>::iterator
is a class type, and it could be a pointer, in which case it cannot be derived from. To be portable, you'd need to define the whole iterator API yourself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With