可以在各种“ if”语句中做同样的事情吗?

时间:2019-01-25 20:52:45

标签: c++ if-statement

当我遇到这个问题时我正在编码,我想知道这是正确的还是出于性能原因可以改进:

if (color == 0) {
    if (c.val[0] >= 0 && c.val[0] <= 64) {
        //Black
        Paint(cursor.x + x, cursor.y + y);
    }
}
else if (color == 1) {
    if (c.val[0] >= 64 && c.val[0] <= 128) {
        //Grey
        Paint(cursor.x + x, cursor.y + y);
    }
}
else if (color == 2) {
    if (c.val[0] >= 128 && c.val[0] <= 192) {
        //White Gray
        Paint(cursor.x + x, cursor.y + y);
    }
}

您可以看到即时消息在所有IF语句中执行的操作完全相同,而且看起来有点怪异,该程序可以按我的意愿工作,但我真的认为即时消息缺少某些内容。

谢谢!

7 个答案:

答案 0 :(得分:5)

由于结构,

if (color >= 0 && color <= 2) {
    if (c.val[0] >= 64*color && c.val[0] <= 64*(color+1)) {
        Paint(cursor.x + x, cursor.y + y);
    }
}

答案 1 :(得分:1)

一些逻辑运算使其更紧凑。

        if ((color == 0 && c.val[0] >= 0 && c.val[0] <= 64) ||
            (color == 1 && c.val[0] >= 64 && c.val[0] <= 128) ||
            (color == 2 && c.val[0] >= 128 && c.val[0] <= 192)) {
                Paint(cursor.x + x, cursor.y + y);
        }

答案 2 :(得分:0)

重复这么短的代码并不太可怕,但是出于“不要重复自己”的考虑,并且如果以后需要更多代码,则可以简单地将测试分开,以决定是否要执行某些操作从实际操作中,使用标志。

bool need_Paint = false;
if (color == 0) {
    // Black?
    need_Paint = (c.val[0] >= 0 && c.val[0] <= 64);
}
else if (color == 1) {
    // Grey?
    need_Paint = (c.val[0] >= 64 && c.val[0] <= 128);
}
else if (color == 2) {
    // White Gray?
    need_Paint = (c.val[0] >= 128 && c.val[0] <= 192);
}

if (need_Paint)
    Paint(cursor.x + x, cursor.y + y);

(请注意,编译器的优化可能无需实际将bool放入内存中就可以处理这种事情,如果合适的条件为真,则直接跳转到函数调用语句。)

(这看起来也像通常写成switch的那种模式。您可以考虑使用该语法而不是所有的if。)

但是实际上,这个特定的代码可以变得更加简单,因为您正在执行的三个不同测试具有直接的数学模式:

if (color >= 0 && color <= 2 && // (if these aren't already guaranteed)
    c.val[0] >= 64*color && c.val[0] <= 64*(color+1)) {
    Paint(cursor.x + x, cursor.y + y);
}

(要考虑的另一件事可能是使用enum ColorType { BLACK=0, GREY=1, WHITE_GRAY=2 };而不是直接写“幻数” 012。但是如果同时使用enum和此代码的数学版本,尽管enum的默认值始终从零开始连续计数,但我还是建议您指定显示的确切值,以使您清楚重新指望那些值。)

答案 3 :(得分:0)

我更喜欢您的原始帖子,而不是所选内容。

这是另一种方法,具有大约相同的行数...但是我发现它更具可读性。

void yourSnippet() {
     switch (color) {
     case 0: { PaintIf(  0,  64); } break; // black
     case 1: { PaintIf( 64, 128); } break; // Grey
     case 2: { PaintIf(128, 192); } break; // White Gray
     } // switch
  }

void PaintIf(int min, int max) {
     if ((c.val[0] >= min) && (c.val[0] <= max)) 
        Paint(cursor.x + x, cursor.y + y);
  }

答案 4 :(得分:0)

另一个与2785528's answer相似的解决方案,但使用lambda以避免将其他参数传递给PaintIf

const auto PaintIf = [&](int min, int max)
{
    if (min <= c.val[0] && c.val[0] <= max) 
        Paint(cursor.x + x, cursor.y + y);
};

switch (color)
{
    case 0: PaintIf(  0,  64); break;
    case 1: PaintIf( 64, 128); break;
    case 2: PaintIf(128, 192);
}

答案 5 :(得分:0)

(从c ++ 17开始)尽可能保证Lambda是constexpr(即零成本抽象)。

它们有时可以允许更简洁和可维护的逻辑表达:

auto range = [](int color)
{
    auto min = color * 64;
    auto max = min + 64;
    return std::make_tuple(min, max);
};

auto in_range = [](auto val, auto tuple)
{
    auto [min, max] = tuple;
    return val >= min && val <= max;
};

if (in_range(c.val[0], range(color)))
    Paint(cursor.x + x, cursor.y + y);

答案 6 :(得分:-1)

vector<int> limits = {0, 64, 128, 192};

if (0 <= color && color <= 2) {
    if (c.val[0] >= limits[color] && c.val[0] <= limits[color + 1]) {
        Paint(cursor.x + x, cursor.y + y);
    }
}

解决这个问题的方法如下:代码中不应有未命名的常量(嗯,至少最好避免使用它们)。然后您会注意到其中有很多,因此将它们存储在数组中是合乎逻辑的。