Ответ 1
Проблема, насколько мне известно, заключается в том, что вы не используете конструкцию range-for соответствующим образом.
Сделаем шаг назад:
void foo(std::vector<int> const& v) {
for (int i: v) {
}
}
Обратите внимание, как диапазон - для итерации по вектору для извлечения целых чисел.
По каким-то причинам вы решили не применять итераторы для перехода от begin
в end
, а вместо этого повторно использовать копию того, что вы итерируете, даже если оно немного меняется, и вы делаете тонна дополнительной работы (в копии и проверки)...
Примечание: std::iterator<double, ...>
означает, что operator*
должен вернуть double&
.
Если вы хотите использовать новую идиому, вам придется соответствовать ее ожиданиям.
Ожидается, что вы повторяете итераторы , а не копируете исходный объект (слегка измененный) снова и снова. Это идиома С++.
Это означает, что вам нужно будет порезать свой объект пополам: вытащите все, что является неизменным во время итерации в объекте, который нужно повторить и что изменилось в итераторе.
Из того, что я вижу:
-
_lower
,_upper
и_delta
фиксированы -
_state
- это итерационная переменная
Следовательно, у вас будет:
template <typename> class NumericRangeIterator
template <unsigned N> // makes no sense having a negative here
class NumericRange {
public:
template <typename> friend class NumericRangeIterator;
typedef NumericRangeIterator<NumericRange> iterator;
typedef NumericRangeIterator<NumericRange const> const_iterator;
static unsigned const Size = N;
// ... constructors
iterator begin(); // to be defined after NumericRangeIterator
iterator end();
const_iterator begin() const;
const_iterator end() const;
private:
std::array<double, N> _lower, _upper, _delta;
}; // class NumericRange
template <typename T>
class NumericRangeIterator: public
std::iterator< std::array<double, T::Size>,
std::forward_iterator_tag >
{
public:
template <unsigned> friend class NumericRange;
NumericRangeIterator(): _range(0), _state() {}
NumericRangeIterator& operator++() {
this->advance();
return *this;
}
NumericRangeIterator operator++(int) {
NumericRangeIterator tmp(*this);
++*this;
return tmp;
}
std::array<double, T::Size> const& operator*() const {
return _state;
}
std::array<double, T::Size> const* operator->() const {
return _state;
}
bool operator==(NumericRangeIterator const& other) const {
return _state != other._state;
}
bool operator!=(NumericRangeIterator const& other) const {
return !(*this == other);
}
private:
NumericRangeIterator(T& t, std::array<double, T::Size> s):
_range(&t), _state(s) {}
void advance(unsigned index = T::Size - 1); // as you did
void in_range(unsigned index = T::Size - 1); // as you did
T* _range;
std::array<double, T::Size> _state;
}; // class NumericRangeIterator
template <unsigned N>
auto NumericRange<N>::begin() -> typename NumericRange<N>::iterator {
return iterator(*this, _lower);
}
template <unsigned N>
auto NumericRange<N>::end() -> typename NumericRange<N>::iterator {
return iterator(*this, _upper);
}
И со всей этой настройкой вы можете написать:
for (auto const& state: nr) {
}
Где auto
будет выведено как std::array<double, nr::Size>
.
Примечание: не уверены, что iterator
полезны, может быть, только const_iterator
, так как это ложная итерация в некотором роде; вы не можете попасть в объект диапазона, чтобы изменить его через итератор.
РЕДАКТИРОВАТЬ: operator==
работает слишком медленно, как получить его лучше?
Я предлагаю обмануть.
1/Измените конструкторы итератора
NumericRangeIterator(): _range(0), _state() {} // sentinel value
NumericRangeIterator(T& t): _range(&t), _state(t._lower) {}
2/Измените итерацию, чтобы создать новое значение "дозорного" в конце
void advance() {
// ...
if (not this->in_range()) { // getting out of the iteration ?
*this = NumericRangeIterator(); // then use the sentinel value
}
}
3/Измените определение begin
и end
соответственно
template <unsigned N>
auto NumericRange<N>::begin() -> typename NumericRange<N>::iterator {
return iterator(*this);
}
template <unsigned N>
auto NumericRange<N>::end() -> typename NumericRange<N>::iterator {
return iterator();
}
4/Сделайте ==
более равным с помощью часового
bool operator==(NumericRangeIterator const& other) const {
return _range == other._range and _state == other._state;
}
Теперь, все время итерации ==
закорачивается, потому что один из _range
является нулевым, а другой - нет. Только при последнем вызове на самом деле происходит сравнение двух атрибутов _state
.