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

时间:2015-08-04 16:49:19

标签: 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]
} 

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

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

6 个答案:

答案 0 :(得分:39)

您可以编写一个可变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, ...)一样使用它。它还具有能够采取任何条件的优点。

Here's a demo

答案 1 :(得分: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;
}

这可以通过注意到0-15范围之外的所有值都设置为不是四个最不重要的值中的一个,并且范围内的所有值都不是。

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

答案 2 :(得分: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;
}

然后使用它代替你的长期条件:

if (isInBounds(a, b, c, d, e))
{
    // do things with array[a][b][c][d][e]
}

答案 3 :(得分:9)

您可以将变量存储为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

答案 4 :(得分: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之类的东西,而不是管理五个整数。

答案 5 :(得分:1)

如果出现的数量为abcde 经常在一起,所有人都需要保持在界限内 你的“世界”(例如他们代表那个世界中某些东西的“状态”) 那么定义一个主要目的的类可能是有意义的 持有一个由这五个数量组成的“国家”。

然后确保如果任何代码尝试在对象中存储值 不属于界限的那一类,是合理的 (而不是段错)反而发生了, 并且没有超出范围的值存储在那里。 这样,该类的对象可以安全地传递给任何函数 要求abcde在范围内, 并且不需要任何这样的函数来进行边界检查 关于这五个价值观。