使用map <string,int>在switch-case语句中使用字符串

时间:2016-12-20 09:25:06

标签: c++

由于我们不能直接在switch-case语句中使用字符串,因为它们无法计算常量,因此我将条目映射到map<string,int>

map<string,int> hash;
    hash["+x"] = 0;
    hash["-x"] = 1;
    hash["+y"] = 2;
    hash["-y"] = 3;
    hash["+z"] = 4;
    hash["-z"] = 5;

现在,我在switch-case表达式中使用它们:

cin >> bend //assume user entered +x
switch(hash[bend])
            {
                case hash["+y"] :
                    switch(pointedto)
                    {
                        case hash["+x"]: pointedto = hash["+y"];
                            break;
                        case hash["-x"]: pointedto = hash["-y"];
                            break;
                        case hash["+y"]: pointedto = hash["-x"];
                            break;
                        case hash["-y"]: pointedto = hash["+x"];
                            break;
                        case hash["+z"]: pointedto = hash["+z"];
                            break;
                        case hash["-z"]: pointedto = hash["-z"];
                            break;                  
                    }
            }

我收到错误: 所有an array reference cannot appear in a constant-expression的{​​{1}}。我期待case和其他人返回hash["+x"],这将导致一个常量。

PS:另一种选择是来自int的{​​{1}},但我很想使用这个。

3 个答案:

答案 0 :(得分:4)

此特定代码示例中的问题是case值应该是编译时常量。 std::map::operator[]返回的值不是,因此不能在case子句中使用。

您可以使用基于constexpr的方法,如下所示:

constexpr array<double, 10> values = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};

constexpr int f(double f) {
    for (int i = 0; i < 10; ++i) {
        if (values[i] == f) {
            return i;
        }
    }
    return -1;
}

double x = 4.0;
switch (f(x)) {
case f(1.0) :
    break;
case f(2.0) :
    break;
    ...
default :
    break;
}

但它仅适用于constexpr - 可构造类型。不幸的是,std::string不是其中之一。

答案 1 :(得分:3)

不要与语言作斗争。

C ++ switch语句中的案例标签需要编译时可评估的常量表达式,而C ++标准库std::mapstd::unordered_map则不目前提供。

改为使用if else块。它甚至可能会更快 - 特别是如果您选择最佳订单。

switch 字符数组(例如'+x';请注意单引号字符)经常作为4个字符或更少字符的替代品,但即便如此不便携。

答案 2 :(得分:1)

一些解决方案:

  1. 尽早摆脱字符串。声明enum direction {posX, negX, posY, negY, posZ, negZ}并声明pointedtodirection类型而不是字符串。现在你可以说case posY:是编译时常量,但比case 2:更具可读性。将hash更改为map<string, direction>以解析用户的输入,使用direction执行所有处理,并定义map<direction, string>以在您想要呈现时转换回字符串回答用户。

  2. 认识到搜索地图“有点像”一个开关。包含嵌套开关的开关可以通过映射图(map<direction, map<direction, direction>>)进行模拟,以便所有开关可以用一行替换pointedto = hash[bend][pointedto];或嵌套开关可以用一个带有“复合键”(map<pair<direction, direction>, direction>)的地图替换,以便所有开关都被pointedto = hash[make_pair(bend, pointedto)];替换。这将与bendpointedto一起用作字符串 - 所以hash["+y"]["+x"] == "+y" - 但如果您在用户输入和输出之间进行了多次迭代,则枚举可能会更有效。

  3. 使用巧妙选择的值声明一个枚举,例如enum direction {posX=4, negX=0, posY=5, negY=1, posZ=6, negZ=2},并找到一些聪明的数学来转换弯曲并指向一个新的指向值。 注意:我在此处说明的值仅用于说明目的 - 只有在您真正需要针对性能优化此代码时才应使用此路由。为了完整起见,我提到了这条路线,但如果您决定使用它,则对不眠之夜不承担任何责任:)

  4. 修改

    1. 此:
    2. #include <algorithm>
      #include <iostream>
      #include <map>
      #include <string>
      
      enum direction {posX, negX, posY, negY, posZ, negZ};
      
      const direction transform[6][6]{
          // previous pointed to:                    bend
          // +x    -x    +y    -y    +z    -z        ----
          {                                   },  //  +x
          {                                   },  //  -x
          { posY, negY, negX, posX, posZ, negZ},  //  +y
          {                                   },  //  -y
          {                                   },  //  +z
          {                                   },  //  -z
      };
      
      const std::map<std::string, direction> stringToDirection{ { "+x", posX },{ "-x", negX },{ "+y", posY },{ "-y", negY },{ "+z", posZ },{ "-z", negZ } };
      const std::map<direction, std::string> directionToString{ { posX, "+x" },{ negX, "-x" },{ posY, "+y" },{ negY, "-y" },{ posZ, "+z" },{ negZ, "-z" } };
      
      int main(int, char**) {
          direction pointedto = posY;
      
          std::string bendInput;
          std::cin >> bendInput;
          direction bend = stringToDirection.at(bendInput);
      
          pointedto = transform[bend][pointedto];
      
          std::cout << directionToString.at(pointedto) << "\n";
      
          return 0;
      }
      

      注意:

      • 您必须填写数组初始化的其余部分。
      • 在此示例中,我没有对用户输入进行错误检查。
      • directionToString应该来自stringToDirection,但我想在这里保持简单。