检查大量类似条件的简单方法?

Kai*_*idt 25 c++

我正在开发一个游戏,我发现自己经常检查某些数量是否代表我的世界的向量所接受的索引范围:

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]
} 
Run Code Online (Sandbox Code Playgroud)

我经常要检查比这更多的条件.有没有办法让这些检查更简洁和/或更容易阅读?

或者,有没有办法可以避免完全进行检查?矢量是16x16x16x16x16; 我可以这么做,如果我给它一个16作为索引,它会做什么,而不是段错误?

yiz*_*lez 40

你可以编写一个可变check函数:

bool check(int a) {
  return 0 <= a && a < 16;
}   

template<typename... Args>
bool check(int a, Args... args) {
  return check(a) && check(args...);
}
Run Code Online (Sandbox Code Playgroud)

你可以像使用它一样check(a, b, c, d, e, ...).它还具有能够采取任何条件的优点.

这是一个演示

  • @LưuVĩnhPhúc这确实是一个非常好的性能优化.这就是为什么编译器编写器已经在很长一段时间内应用它并且不必混淆代码的原因. (12认同)

Ada*_*dam 13

这是一种紧凑而有效的检查方法.它假定两个补码算术.

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;
}
Run Code Online (Sandbox Code Playgroud)

这通过注意到0-15范围之外的所有值都具有不是四个最不重要的值之一的位集合而且该范围内的所有值都没有.

当然,如果效率的提高超过代码可读性的损失,那么仅使用这种优化是值得的.


Jas*_*zun 11

功能点是可重用性.如果您发现自己反复编写某些长表达式或语句组,则可能需要重构它.

在这种情况下,我会编写一个简单的函数来进行边界检查:

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;
}
Run Code Online (Sandbox Code Playgroud)

然后使用它而不是你的长期条件:

if (isInBounds(a, b, c, d, e))
{
    // do things with array[a][b][c][d][e]
}
Run Code Online (Sandbox Code Playgroud)


Gal*_*lik 9

您可以将变量存储为std :: vector中的元素,而不是像这样单独的变量:

bool test(const std::vector<int>& values)
{
    for(auto v: values)
        if(v < 0 || v >= 16)
            return false;
    return true;
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您使用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
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您也可以使用std :: array.


Chr*_*rew 5

您可以将构成索引的5个整数组合到一个std::array或您自己的类中.

using Index5 = std::array<int, 5>;
Run Code Online (Sandbox Code Playgroud)

然后你可以写一个像这样的函数:

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;
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

auto bounds = Index5{16, 16, 16, 16, 16};
auto point = Index5{a, b, c, d, e};

if (contains(bounds, point)) {
    // do things with point
}
Run Code Online (Sandbox Code Playgroud)

一般来说,我建议使用类似的东西,Index5而不是管理五个整数.