Подтвердить что ты не робот

Простой способ проверить большое количество подобных условий?

Я работаю над игрой, и я очень часто проверяю, что определенные количества находятся в пределах индексов, принятых вектором, который представляет мой мир:

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?

4b9b3361

Ответ 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 находились в пределах границ, и нет никакой необходимости в том, чтобы какая-либо такая функция выполняла проверку границ на эти пять значений.