Простой способ проверить большое количество подобных условий?
Я работаю над игрой, и я очень часто проверяю, что определенные количества находятся в пределах индексов, принятых вектором, который представляет мой мир:
if(a >= 0 && a < 16 && b >= 0 && b < 16 && c >= 0 && c < 16 &&
d >= 0 && d < 16 && e >= 0 && e < 16)
{
//do things with vector[a][b][c][d][e]
}
Мне часто приходится проверять еще больше условий, чем это. Могу ли я сделать эти проверки более краткими и/или более легкими для чтения?
В качестве альтернативы, есть ли способ, которым я могу избежать проверки полностью? Вектор 16x16x16x16x16; могу ли я сделать так, чтобы, если бы я дал ему 16 в качестве индекса, он ничего не сделал бы, а не segfault?
Ответы
Ответ 1
Вы можете написать переменную check
функцию:
bool check(int a) {
return 0 <= a && a < 16;
}
template<typename... Args>
bool check(int a, Args... args) {
return check(a) && check(args...);
}
Вы можете использовать его как check(a, b, c, d, e, ...)
. Это также имеет то преимущество, что вы можете принять любое количество условий.
Здесь демо
Ответ 2
Здесь представлен компактный и эффективный способ проверки. Он предполагает две арифметические дополнения.
bool IsInBounds(int a, int b, int c, int d, int e)
{
// Make sure only bits 0-3 are set (i.e. all values are 0-15)
return ((a | b | c | d | e) & ~0xf) == 0;
}
Это работает, отмечая, что все значения вне диапазона 0-15 имеют бит, который не является одним из четырех наименее значимых, и все значения внутри диапазона не имеют.
Конечно, стоит использовать эту оптимизацию только в том случае, если выигрыш в эффективности перевешивает потерю удобочитаемости кода.
Ответ 3
Точка функций является многократной. Если вы часто повторяете некоторые длинные выражения или группы утверждений, возможно, пришло время реорганизовать его.
В этом случае я бы написал простую функцию для проверки границ:
bool isInBounds(int a, int b, int c, int d, int e)
{
return a >= 0 && a < 16 &&
b >= 0 && b < 16 &&
c >= 0 && c < 16 &&
d >= 0 && d < 16 &&
e >= 0 && e < 16;
}
Затем используйте его вместо вашего длительного условия:
if (isInBounds(a, b, c, d, e))
{
// do things with array[a][b][c][d][e]
}
Ответ 4
Вы можете хранить переменные как элементы в std::vector, а не отдельные переменные вроде этого:
bool test(const std::vector<int>& values)
{
for(auto v: values)
if(v < 0 || v >= 16)
return false;
return true;
}
Альтернативно, если вы используете C++11
или позже, вы можете использовать std:: all_of:
if(std::all_of(std::begin(values), std::end(values),
[](int i){ return i >= 0 && i < 16; }))
{
// do stuff with values
}
В этом случае вы также можете использовать std:: array.
Ответ 5
Вы могли бы объединить 5 целых чисел, составляющих ваш индекс, в один std::array
или ваш собственный класс.
using Index5 = std::array<int, 5>;
Тогда вы можете написать такую функцию, как:
bool contains(Index5 bounds, Index5 point) {
for (Index5::size_type d = 0; d != bounds.size(); ++d) {
if ((unsigned)point[d] > bounds[d]) // using the trick mentioned in comments
return false;
}
return true;
}
Затем используйте его следующим образом:
auto bounds = Index5{16, 16, 16, 16, 16};
auto point = Index5{a, b, c, d, e};
if (contains(bounds, point)) {
// do things with point
}
В общем, я бы предложил использовать что-то вроде Index5
вместо управления пятью целыми числами.
Ответ 6
Если величины a
, b
, c
, d
и e
- это нечто, что происходит
вместе довольно часто и все должны оставаться в пределах
вашего "мира" (например, они представляют "состояние" чего-то в этом мире)
то имеет смысл определить класс, основной целью которого является
провести одно "состояние", состоящее из этих пяти величин.
Затем убедитесь, что если какой-либо код когда-либо пытается сохранить значения в объекте
этого класса, которые не находятся в пределах границ, что-то разумное
(а не segfault) происходит вместо этого,
и никакие значения вне пределов не хранятся там.
Таким образом, объект этого класса безопасен для перехода к любой функции, которая
требует, чтобы a
, b
, c
, d
и e
находились в пределах границ,
и нет никакой необходимости в том, чтобы какая-либо такая функция выполняла проверку границ
на эти пять значений.