Reputation: 753
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
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