为什么开关大小写语句中不能有变量?

Why can't I have a variable in switch-case statement?

本文关键字:变量 不能 开关 大小写 语句 为什么      更新时间:2023-10-16

这是我的代码:

bool Character::keyPress(char c)
{
    switch(c)
    {
        case up_key:
            move(0, -1);
            break;
        case down_key:
            move(0, 1);
            break;
        case left_key:
            move(-1, 0);
            break;
        case right_key:
            move(1,0);
            break;
        default:
            return false;
    }
    return true;
}

编译器抱怨道:

error C2051: case expression not constant
error C2051: case expression not constant
error C2051: case expression not constant
error C2051: case expression not constant

在我的头文件中,我有:

protected:
    char up_key;
    char down_key;
    char right_key;
    char left_key;

我使用的是Visual C++2008。

正如错误消息所述,大小写表达式必须是常量。编译器在编译时将其构建为一个非常快速的查找表,如果值可能随着程序的运行而更改,则无法做到这一点。

如果您确实需要它们是可变的,而不是恒定的,那么最好使用If/else语句。

替换这个冗长笨拙的代码,

switch(c)
{
    case up_key:
        move(0, -1);
        break;
    case down_key:
        move(0, 1);
        break;
    case left_key:
        move(-1, 0);
        break;
    case right_key:
        move(1,0);
        break;
    default:
        return false;
}

像这样的东西:

move( (c==right_key) - (c==left_key) , (c==down_key) - (c==up_key) );

您可以随意地用更整洁的单行代码替换这17行长的代码。

你不能,因为语言不是这样工作的。例如,如果up_keydown_keyright_keyleft_key都相等,会发生什么?

因为switch语句只能取常量,所以在读取代码时,您知道要比较的东西都是常量。另一方面,您可以使用if语句(或其他结构)与变量进行比较:

if (c == up_key) {
    move(0, -1);
} else if (c == down_key) {
    move(0, 1);
} else ...

这提供了一个明显的结构差异,可以极大地帮助后面的人阅读代码。想象一下,如果你必须查找每个case标签,看看它是否是一个变量?

我相信这是因为编译器生成了一个带有硬编码值的跳转表,尽管我可能错了。生成表格的方式不允许这样做。

由于其他答案已经涵盖了出现错误的原因,因此有一种方法可以在按键时向四个方向之一移动:使用查找表而不是条件/开关。

设置部分:

std::map<char,pair<int,int> > moves;
moves[up_key] = make_pair(0, -1);
moves[down_key] = make_pair(0, 1);
moves[left_key] = make_pair(-1, 0);
moves[right_key] = make_pair(1, 0);

功能:

bool Character::keyPress(char c) {
    if (moves.count(c)) {
        pair<int,int> dir = moves[c];
        move(dir.first, dir.second);
        return true;
    } else {
        return false;
    }
}
//here is the full functional code snippet which can be compiled and run with most of C++  
//compiler/link ...console app was demoed but you can apply the code/logic to win32 app...
//if you have any problem, send me email to Samuel_Ni@yahoo.com
#include <iostream.h>
#include <map>
#include <conio.h>
class CkbdHanler{
  private:
    map<char,pair<int,int> > moves;
  protected:
    char up_key;
    char down_key;
    char right_key;
    char left_key;
  public:
CkbdHanler(char a,char b,char c,char d):up_key(a),
                                        down_key(b),
                                       right_key(c),
                                       left_key(d)
{
    moves[up_key] = make_pair(0, -1);
    moves[down_key] = make_pair(0, 1);
    moves[left_key] = make_pair(-1, 0);
    moves[right_key] = make_pair(1, 0);
 }
bool keyPress(char c){
    if (moves.count(c)) {
            pair<int,int> dir = moves[c];
            move(dir.first, dir.second);
            return true;
   } else return false;
}
void move(int i,int j){
   cout<<"(i,j)=("<<i<<","<<j<<")"<<endl;
  }
};
int main(int argc, char* argv[])
{
  CkbdHanler CmyKbdH('u','d','l','r');
  cout << "Hello C++... here is a demo of Map to replace switch-case" << endl;
  CmyKbdH.keyPress('d');
  cout << endl << "Press any key to continue...";
  getch();
  return 0;
}