【问题标题】:Why can't I have a variable in switch-case statement? [duplicate]为什么我不能在 switch-case 语句中有一个变量? [复制]
【发布时间】:2012-01-19 04:03:25
【问题描述】:

这是我的代码:

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。

【问题讨论】:

  • switch case 表达式必须是编译时常量。将它们更改为static const char up_key = 1; 等,问题就解决了。
  • 因为标准是这样说的。这是旧时代的残余,switch 被引入作为“更好”的演示文稿,它被自动转换为数组查找(因此需要常量)。现在它已经不太有意义了,但是语法没有改变所以......

标签: c++ switch-statement


【解决方案1】:

正如错误消息所述,case 表达式必须是常量。编译器在编译时将其构建为一个非常快速的查找表,如果在程序运行时值可能会发生变化,它就无法做到这一点。

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

【讨论】:

  • 在这种情况下是否有可能以某种方式“看到”编译器的输出,并将其与 if/else 进行比较?
【解决方案2】:

替换掉这个又长又笨的代码,

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 行代码。

【讨论】:

  • 是什么让你觉得这段代码很简洁?
  • 一条简洁的线-也许您应该在代码中添加一个小的解释性注释以帮助难以阅读的类型;)
  • 不会增加时间复杂度吗? 4个比较,4个类型转换和2个算术运算将用你的单行进行!
  • @neckTwi 我认为这些额外的操作并不重要,因为按键并不经常发生。 (那么编译器也有可能将该行优化为与上面的 switch–case 语句等效的东西,尽管我不知道你能相信它实际上做了多少)
  • @EralpB 它很整洁,因为它包含的代码更少- 容易发生,因为您需要对更少的地方进行更改。
【解决方案3】:

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

【讨论】:

  • ,我明白你的意思。但是如果我使用 if/else 并且它们都是平等的??
  • 实际上,您可以在这里多次使用相同的值,尽管您总是会出现在列表中的第一个。使用 if/else 时,您也将到达第一个,而永远不会到达后面的。
  • 即使它们都是常数,这是这里的关键方面,案例中的值必须都是不同的。但独特性不是问题——它是缺乏一致性。
  • 你不能有两次相同的常数?我相信 GCC 允许这样做,尽管现在你让我不确定。
【解决方案4】:

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

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

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

【讨论】:

  • 是的,这就是我要做的,谢谢。
【解决方案5】:

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

【讨论】:

    【解决方案6】:

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

    设置部分:

    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;
        }
    }
    

    【讨论】:

      【解决方案7】:
      //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;
      }
      

      【讨论】:

        猜你喜欢
        • 2021-11-24
        • 1970-01-01
        • 2014-11-10
        • 2017-04-13
        • 1970-01-01
        • 1970-01-01
        • 2011-08-02
        相关资源
        最近更新 更多