Meine Empfehlung ist, dass Sie Iteratoren verwenden, schrieb ich ein Beispiel unten. So etwas wie dies tun würde, es in C++ < C++ 17:
#include <iostream>
template <class T>
struct RangeIter {
RangeIter(T from, T to, T curr) :
_from(from), _to(to), _curr(curr) {
}
T operator*() const {
return _curr;
}
T operator++() {
++_curr;
return _curr;
}
bool operator==(const RangeIter & other) {
assert(_from == other._from && _to == other._to);
return _curr == other._curr;
}
bool operator!=(const RangeIter & other) {
return !(_curr == other._curr);
}
T _from, _to, _curr;
};
template <class T>
struct Range {
Range(T from, T to) : _from(from), _to(to) {}
RangeIter<T> begin() { return RangeIter<T>(_from, _to, _from); }
RangeIter<T> end() {
return RangeIter<T>(_from, _to, _to);
}
T _from, _to;
};
template <class T>
Range<T> makeRange(T to, T from) {
return Range<T>(to, from);
}
int main() {
for (auto i : makeRange(0, 10)) {
std::cout << i << std::endl;
}
}
Für C 17 ++ Sie verschiedene Typen für den Beginn und das Ende Iterator und verbessern auf diese nutzen können. Sie können Sentinels verwenden. Sie könnten einen Blick hier: How the new range-based for loop in C++17 helps Ranges TS?
A C++ - 17 einzige Lösung hier:
#include <iostream>
template <class T>
struct RangeSentinel {
RangeSentinel(T stopVal) : _stopVal(stopVal) {}
T _stopVal;
};
template <class T>
struct RangeIter {
RangeIter(T from, T to, T curr) :
_from(from), _to(to), _curr(curr) {
}
T operator*() const {
return _curr;
}
T operator++() {
++_curr;
return _curr;
}
bool operator==(const RangeSentinel<T> & other) {
assert(_from == other._from && _to == other._to);
return _curr == other._stopVal;
}
bool operator!=(const RangeSentinel<T> & other) {
return !(_curr == other._stopVal);
}
T _from, _to, _curr;
};
template <class T>
struct Range {
Range(T from, T to) : _from(from), _to(to) {}
RangeIter<T> begin() { return RangeIter<T>(_from, _to, _from); }
RangeSentinel<T> end() {
return RangeSentinel<T>(_to);
}
T _from, _to;
};
template <class T>
Range<T> makeRange(T to, T from) {
return Range<T>(to, from);
}
int main() {
for (auto i : makeRange(0, 10)) {
std::cout << i << std::endl;
}
}
Wie Sie sehen können, in der C++ 17-Lösung Ich brauche nicht noch einmal speichern _From und _to Variablen , da der Sentinel ein anderer Typ ist.
Meine starke Meinung folgt: Verwenden von Makros, um den Quellcode kürzer zu machen, ist eine sehr schlechte Idee. Es verbirgt Dinge, die Sie sehen wollen und macht das Finden von Fehlern zu einem echten Schmerz im Hintern. Makros haben Verwendung, aber das ist nicht gut. –
Eigentlich möchte ich es einfacher machen –
Für diesen speziellen Fall könnten Sie 'für (automatische Zeile: boost :: irange (0, a.size()))' –