David
David

Reputation: 753

How to inherit from c++ iterator class?

Below I depict the general structure of my code:

class OperandIterator : public std::iterator<std::input_iterator_tag, pOpReference>
{
public:
    OperandIterator(...)...
    OperandIterator & operator++();  // also calls to advance()
    OperandIterator operator++(int); // also calls to advance() 
    bool operator==(const OperandIterator & other) const;
    bool operator!=(const OperandIterator & other) const;
    pOpReference operator*();
protected:
    virtual void advance();
}

class OperandSpecialIterator : public OperandIterator 
{
public:
     ...    
private:
    void advance() override; // this is the only diffrence between the classes
}

class TraversalPattern
{
 public:
       TraversalPattern(Operand op, Order order, bool specialTraversal);
       OperandIterator begin() { return specialTraversal ? OperandSpecialIterator(...) : OperanInerator(...); }
}


// somewhere
TraversalPattern p(...specialTraversal=ture);
OperandIterator iter = p.begin();
it++;

Even though begin() function returns OperandSpecialIterator, when it++ performed the advance function that is being called is the advance function of OperandIterator. The problem is that begin() can't return a reference. The question is: Can begin function return iterators of different types?

Upvotes: 2

Views: 337

Answers (1)

n314159
n314159

Reputation: 5085

What you are asking is not possible. The begin() function cannot return different types depending on a runtime value. What you could do, is implement something like a VariantIterator that can hold different types of operators in an std::variant (C++17) and forwards the iterator operations to the currently held iterator.

For this simple case, I personally would do the advancing by passing a function pointer to my Iterator:

class OperandIterator; // forward declaration

namespace advancers { // Forward declarations since definition only works, 
      // when OperandIterator is defined. You can make this easier by making
      // these methods static in the class. I declare them forward to be able
      // to use them as defaults in OperandIterator.
  void advance_normally(OperandIterator& it);

  void advance_specially(OperandIterator &it);
} // End namespace advancers

class OperandIterator : public std::iterator<std::input_iterator_tag, pOpReference>
{
public:
  OperandIterator() = default;
  OperandIterator(void (*advanc_fnc)(OperandIterator&)) : advancer(advanc_fnc) {}
  OperandIterator & operator++();  // also calls advancer with *this
  OperandIterator operator++(int); // also calls advancer with *this 
private:
  const void (*advancer)(OperandIterator&) = &advancers::advance_normally;
}

namespace advancers { // Definitions
  void advance_normally(OperandIterator& it) {
    it++;
  }

  void advance_specially(OperandIterator &it) {
    // Something else
  }
} // End namespace advancers



OperandIterator make_special() {
  return OperandIterator(&advancers::advance_specially);
}

class TraversalPattern
{
 public:
       TraversalPattern(Operand op, Order order, bool specialTraversal);
       OperandIterator begin() { return specialTraversal ? OperandSpecialIterator() : make_special(); }
}


// somewhere
TraversalPattern p(...specialTraversal=ture);
OperandIterator iter = p.begin();
it++;

The nice thing about this is, that you can easily add more versions of advancing and even make them in place with a lambda.

Upvotes: 1

Related Questions