有状态 C++ 输入迭代器 post 增量问题
Stateful C++ Input Iterators post increment problem
我正在实现一个迭代器,该迭代器采用另一个浮点值生成输入迭代器,如果检测到上升,则 returns 为真。因此,迭代器作为软件 ADC(模拟数字转换器)有效地工作。
我已将实际代码最小化为以下内容:
#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_;
};
如您所见,我需要缓存最后一个模拟值。
如果有人以这种方式使用迭代器:
std::vector<float> v = {...};
auto f = ADCFilter(0.2f, v.begin());
while(true) {
std::cout << *f++; // <- post inc
}
缓存值永远不会存储,因为它只存在于返回的副本中。
尽管使用预增量不会发生此问题,因为我们正在取消引用实际的迭代器而不是它的副本。
我可以通过不实现它来轻松禁止使用 post 增量运算符,但根据 https://en.cppreference.com/w/cpp/named_req/InputIterator 它必须为输入迭代器实现。
所以,问题是我如何正确地实现一个像 filter/mapper 到另一个输入迭代器的有状态输入迭代器?
这可以通过重新实现运算符来完成,这样它的内部数据只保存 bool
值,而不是仅当迭代器获取时从中导出 bool
值的浮点值取消引用。
换句话说,解引用迭代器应该是:
bool operator*() const // It should be const, by the way
{
return value;
}
// ...
private:
bool value;
构造函数将 value
初始化为 false
。当前在取消引用运算符中的所有代码基本上都移到了 operator++()
中,其最终结果是更新后的 value
。没有必要保存被迭代的实际值的副本,operator++
可以简单地将包装迭代器引用的当前值与包装迭代器递增后的新值进行比较,并更新 value
.
post-增量++
运算符保持不变。
我正在实现一个迭代器,该迭代器采用另一个浮点值生成输入迭代器,如果检测到上升,则 returns 为真。因此,迭代器作为软件 ADC(模拟数字转换器)有效地工作。
我已将实际代码最小化为以下内容:
#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_;
};
如您所见,我需要缓存最后一个模拟值。 如果有人以这种方式使用迭代器:
std::vector<float> v = {...};
auto f = ADCFilter(0.2f, v.begin());
while(true) {
std::cout << *f++; // <- post inc
}
缓存值永远不会存储,因为它只存在于返回的副本中。 尽管使用预增量不会发生此问题,因为我们正在取消引用实际的迭代器而不是它的副本。
我可以通过不实现它来轻松禁止使用 post 增量运算符,但根据 https://en.cppreference.com/w/cpp/named_req/InputIterator 它必须为输入迭代器实现。
所以,问题是我如何正确地实现一个像 filter/mapper 到另一个输入迭代器的有状态输入迭代器?
这可以通过重新实现运算符来完成,这样它的内部数据只保存 bool
值,而不是仅当迭代器获取时从中导出 bool
值的浮点值取消引用。
换句话说,解引用迭代器应该是:
bool operator*() const // It should be const, by the way
{
return value;
}
// ...
private:
bool value;
构造函数将 value
初始化为 false
。当前在取消引用运算符中的所有代码基本上都移到了 operator++()
中,其最终结果是更新后的 value
。没有必要保存被迭代的实际值的副本,operator++
可以简单地将包装迭代器引用的当前值与包装迭代器递增后的新值进行比较,并更新 value
.
post-增量++
运算符保持不变。