Как наследовать от итератора класса С ++? - PullRequest
2 голосов
/ 15 января 2020

Ниже я изобразил общую структуру моего кода:

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++;

Несмотря на то, что функция begin () возвращает OperandSpecialIterator, когда он ++ выполнял вызываемую функцию продвижения, она является функцией продвижения OperandIterator. Проблема в том, что begin () не может вернуть ссылку. Вопрос в следующем: Может ли функция возвращать итераторы разных типов?

1 Ответ

1 голос
/ 15 января 2020

То, что вы спрашиваете, невозможно. Функция begin() не может возвращать различные типы в зависимости от значения времени выполнения. Что вы могли бы сделать, это реализовать что-то вроде VariantIterator, которое может содержать различные типы операторов в std::variant (C ++ 17) и перенаправлять операции итератора текущему итератору.

В этом простом случае я бы лично продвинулся, передав указатель функции моему итератору:

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++;

Приятно то, что вы можете легко добавлять больше версий продвигаться и даже делать их на месте с помощью лямбды.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...