Что бы это ни стоило, вам всегда нужно знать, в каком направлении идти, поэтому вы не сможете избавиться от этих накладных расходов.Тем не менее, переключаясь с макросов, вы можете, по крайней мере, упростить оптимизацию (частично, сделав входные данные const
, чтобы обеспечить складывание дубликатов / похожих условий на них, и частично, предварительно рассчитав «шаговое» расстояние, чтобы исключить некоторыеиз этих условий полностью).
Что касается макросов, то это не так уж плохо (хотя, вероятно, можно использовать ()
или два ...).
По-настоящему "современный"что нужно сделать, это использовать подсчитывающий итератор или что-то, связанное с irange
.
Например, наивная адаптация кода Нила для обеспечения автоматического направления шагаобнаружение:
#include <iostream>
template <class T>
class range
{
private:
class iter
{
private:
T at, step;
public:
iter(T at, T step) : at(at), step(step) {}
bool operator!=(iter const& other) const { return at != other.at; }
T const& operator*() const { return at; }
iter& operator++() { at += step; return *this; }
};
T begin_val;
T end_val;
T step_val;
public:
range(const T begin_val, const T end_val)
: begin_val(begin_val)
, end_val(end_val)
, step_val(begin_val > end_val ? -1 : 1)
{}
iter begin() { return iter(begin_val, step_val); }
iter end() { return iter(end_val, step_val); }
};
int main()
{
for (auto i : range<unsigned>(42, 10))
std::cout << i << ' ';
std::cout << '\n';
}
// Output: 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
Или, если быть откровенным, вы можете просто написать следующее и покончить с этим:
#include <iostream>
int main()
{
for (unsigned int i = 42; i > 10; --i)
std::cout << i << ' ';
std::cout << '\n';
}
// Output: 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11
Все это поймут;никаких трюков не требуется.
В любом случае, и, несмотря на мои примеры выше, я бы действительно советовал , а не , используя неподписанные типы для этого .