0

I'm trying to define an interface for a container, one of which instances will be a vector. A problem is that I want it to be iterable.

struct Iconstraint_iterator {
  using difference_type   = std::ptrdiff_t;
  using value_type    = ref<Expr>;
  using pointer       = value_type *;
  using reference     = value_type &;
  using iterator_category = std::input_iterator_tag;

  virtual ~Iconstraint_iterator() {}
  virtual const value_type &operator*() = 0;
};

struct constraint_iterator : public Iconstraint_iterator {
  using difference_type   = std::ptrdiff_t;
  using value_type    = ref<Expr>;
  using pointer       = value_type *;
  using reference     = value_type &;
  using iterator_category = std::input_iterator_tag;
  using iterator = std::vector<value_type>::const_iterator;

  constraint_iterator(iterator ptr) : ptr(ptr) {}
  virtual const value_type &operator*() { return *ptr; }
private:
  iterator ptr;
};

class IConstraints {
public:
  virtual ~IConstraints() {}
  virtual Iconstraint_iterator begin() const = 0;
  virtual Iconstraint_iterator end() const = 0;
  virtual void push_back(ref<Expr>) = 0;
};

struct Constraints : public IConstraints {
  virtual constraint_iterator begin() const {
    return constraint_iterator(constraints.cbegin());
  }

  virtual Iconstraint_iterator end() const {
    return constraint_iterator(constraints.cend());
  }

  virtual void push_back(ref<Expr> c) { constraints.push_back(c); }
private:
    std::vector< ref<Expr> > constraints;
};

IConstraints is my interface and Constraints is ought to be it's vector-based instance. Consider different code fragments for Constraints::begin() and Constraints::end(), which are both rejected by the compiler as follows.

error: virtual function 'begin' has a different return type ('constraint_iterator')
than the function it overrides (which has return type 'Iconstraint_iterator')
[build]   virtual constraint_iterator begin() const {
[build]           ~~~~~~~~~~~~~~~~~~~ ^
[build] note: overridden virtual function is here
[build]   virtual Iconstraint_iterator begin() const = 0;
[build]           ~~~~~~~~~~~~~~~~~~~~ ^
[build] error: allocating an object of abstract class type 'Iconstraint_iterator'
[build]     return constraint_iterator(constraints.cend());
[build]            ^
[build] note: unimplemented pure virtual method 'operator*' in 'Iconstraint_iterator'
[build]   virtual const value_type &operator*() = 0;

I do not understand why the compiler complains as constraint_iterator inherits Iconstraint_iterator. If my code idea is totally wrong, could you provide another way to make an iterable container interface with vector as one of it's instances?

  • 2
    A covariant return type may be a reference or a pointer. You may not return a derived value type, because the compiler would no longer know the size of the returned type. How many bytes are needed for the value returned by `begin()`? – Drew Dormann Sep 26 '22 at 19:17
  • As this question isn't getting much further attention - you might investigate the [curiously recurring template pattern](https://stackoverflow.com/questions/4173254/what-is-the-curiously-recurring-template-pattern-crtp) as a way to enforce an interface on a class without the restrictions or overhead of inherited virtual functions. – Drew Dormann Sep 26 '22 at 21:52

0 Answers0