I was implementing an iterator that takes another float values producing input iterator and returns true if a rising was detected. So, the iterator works effectively as a Software-ADC (Analog-Digital-Converter).
I've minimized the actual code to the following:
#include <iterator>
template<typename It>
struct ADCFilter
{
using iterator_tag = std::input_iterator_tag;
ADCFilter(const float threshold, It it)
: It_{it}, Threshold_{threshold}, LastAnalogVal_{0}
{}
bool operator*()
{
float analog_val = *It_;
// rising edge
if (analog_val >= Threshold_ && LastAnalogVal_< Threshold_)
{
LastAnalogVal_ = analog_val;
return true;
}
// no rising edge
LastAnalogVal_ = analog_val;
return false;
}
ADCFilter operator++() { ++It_; return *this; }
// Problem is here
ADCFilter operator++(int) {auto self = *this; operator++(); return self; }
private:
It It_;
float Threshold_;
float LastAnalogVal_;
};
As you can see I need to cache the last analog value. And if somebody uses the iterator in such a way:
std::vector<float> v = {...};
auto f = ADCFilter(0.2f, v.begin());
while(true) {
std::cout << *f++; // <- post inc
}
The cached value is never stored as it's only present in the returned copy. This problem doesn't occur though with pre increment because we are dereferencing the actual iterator and not a copy of it.
I could easily prohibit the usage of post increment operator by not implementing it, but according to https://en.cppreference.com/w/cpp/named_req/InputIterator it must be implemented for input iterators.
So, the question is how can I correctly implement a stateful input iterator that acts like a filter/mapper to another input iterator?