为什么C ++ switch语句仅限于常量表达式?

时间:2014-01-24 00:00:19

标签: c++ switch-statement

在我意识到语句需要保持不变之前,我想在switch语句中使用宏函数。示例(不编译):

#define BAND_FIELD1(B)   (10 * B + 1)
...
#define BAND_FIELD7(B)   (10 * B + 7)

int B = myField % 10;
switch (myField) {
    case BAND_FIELD1(B):
        variable1[B] = 123;
        break;
    case BAND_FIELD7(B):
        variable7[B] = 321;
        break;
    ...
}

我宁愿使用if .. else:

if (myField == BAND_FIELD1(B)
    variable1[B] = 123;
else if (myField == BAND_FIELD7(B)
    variable7[B] = 321;

为什么C ++ switch语句仅限于常量表达式?

6 个答案:

答案 0 :(得分:5)

C ++的一个优点是静态检查。 switch语句是一个静态控制流构造,其功能在于能够(静态地)检查是否已经考虑了所有案例,并且能够合理地分组案例(例如,通过公共部分)。

如果要动态检查条件,可以使用各种技术(if语句,条件运算符,关联数组,虚函数等)来完成这些操作。

答案 1 :(得分:5)

  

为什么c ++ switch语句仅限于常量表达式?

因为switch语句执行的检查是静态。这意味着需要在编译时知道表达式。

在C ++ 11中,您可以使用constexpr(如果表达式由其他常量表达式推导),对您有利。例如,考虑这个函数(替换你的#define):

inline constexpr int BAND_FIELD1(int B) {
    return 10 * B + 1;
}

用于以下简化版代码:

constexpr int myField = 0;
constexpr int B = myField % 10;

int variable1 = 0;
switch (myField) {
    case BAND_FIELD1(B):
        variable1 = 123;
        break;
    // ...
    default: break;
}

如您所见,上面的代码will easily compile

答案 2 :(得分:3)

当出现常量时,编译器可以为交换机生成最快的代码 - 例如。跳表或二叉搜索树。

当给定非常量值时,它不能生成比链式if - else语句更快的代码。无论如何你已经掌握了它!

答案 3 :(得分:3)

我的回答是C ++开关是C开关的剩余部分,它是PL / M等古老语言的遗留物。

在我看来,这个案例的唯一性只是一个可以追溯到70年代的构造的偶然副产品。
它并不保证所有案例都被覆盖,特别是考虑到C ++枚举的弱类型。

考虑到在场景后面经常生成的C ++汇编代码堆,认为C ++开关由于性能原因而限于常量,对我来说似乎有点丰富。

许多其他语言在switch语句中支持变量和/或非数字表达式,我没有看到很多程序员抱怨可能重复的案例值。

答案 4 :(得分:0)

为了帮助回答这个问题,请考虑以下事项(如果它是合法的):

int a=15;
int b=16;
int c=15;
int value = a;

switch (value)
{
case a:
    // Value is A
    break;

case b:
    // value is B
    break;

case c:
    // value is C
    break;

default:
    // value is unknown
}

我们永远不会执行C的代码,因为A会被执行。切换的目的是检查具有唯一可测试值的值。它是一个干净的if..else if..else..if..else。

答案 5 :(得分:0)

编译器在编译时分析常数值,以生成优化的查找表和决策树以快速选择案例。 例如,如果不能使用表,则编译器可能会使用3个cpu指令集生成高效的三叉决策树:与一个值进行比较以设置cpu标志,分支到其他情况下的分支,分支到其他情况下的分支或跌倒直到平等的情况。 请记住,C / C ++与性能有关。 也许将来会添加新的语法或扩展编译器,但是标准的进步试图是渐进的,并且不会破坏已经编写的代码,也不会使现有的编译器无效。