Reputation: 685
Which is worse?
Creating copies
#include <vector>
#include <algorithm>
template<class T>
std::vector<T> range(const T start, const T stop, const T step) {
int leaps = ((stop-start)/step);
std::vector<T> output(leaps > 0 ? leaps : -leaps);
std::generate(output.begin(), output.end(), [i = start, step] () mutable {
T num = i;
i+=step;
return num;
});
return output;
}
or repeating (I'm assuming a single calculation).
#include <vector>
#include <algorithm>
template<class T>
std::vector<T> range(const T start, const T stop, const T step) {
int leaps = ((stop-start)/step);
std::vector<T> output(leaps > 0 ? leaps : -leaps);
std::generate(output.begin(), output.end(), [i = start-step, step] () mutable {return i+=step;});
return output;
}
Is there a way to avoid both? Something such as a post-increment operator that behaves as i++
but allows an increment of step
.
// Example
int main() {
std::vector<double> check_range = range(-4.13, 2.13, 0.25);
return 0;
}
Expected
-4.13, -3.88, -3.63, -3.38, -3.13, -2.88, -2.63, -2.38, -2.13, -1.88, -1.63, -1.38, -1.13, -0.88, -0.63, -0.38, -0.13, 0.12, 0.37, 0.62, 0.87, 1.12, 1.37, 1.62, 1.87
Upvotes: 0
Views: 125
Reputation: 303206
In C++20, I'd write it lazily:
template <class T>
auto range(const T start, const T stop, const T step) {
return views::iota(0)
| views::transform([=](int i) -> T{
return i * step + start;
})
| views::take_while([=](T cur){
return cur < stop;
});
}
If you really want a vector
, you can eagerly evaluate that, but you probably don't need all of it at once?
You could also write a generator using coroutines (though generator<T>
isn't in the standard library, need to use like cppcoro):
template <class T>
generator<T> range(T start, const T stop, const T step) {
for (; start < stop; start += stop) {
co_yield start;
}
}
Which, likewise, is a lazy range that can be eagerly evaluated into a vector
if you really want.
Upvotes: 2
Reputation: 62884
Have a look at boost::irange
. If that doesn't do what you need, you can do some arithmetic.
template<class T>
auto range(const T start, const T stop, const T step) {
int leaps = ((stop-start)/step);
auto toT = [start, step](int i) { return start + (i * step); };
return boost::irange(0, leaps > 0 ? leaps : -leaps) | boost::adaptors::transformed(toT);
}
Upvotes: 0