2016-12-20 40 views
3

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

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所有case秒。我期待hash["+x"]和其他人,返回int这将导致一个常数。

PS:另一种方法是从C++11constexpr,但我很好奇,想用这个。

+2

常量表达式可以在编译时进行评估。 'std :: map :: operator []'不是这些东西之一。 – DeiDei

+0

_I期待hash [“+ x”]等,返回int *,这将导致一个常量。* _什么让你期望有[“something”]将导致常数= –

+0

它*是*可能创建一个可以通过产生常量表达式的字符串进行索引的映射。创建它需要一点努力。我的[CppCon 2016](https://cppcon.org/2016program/)展示了如何创建基本版本。 [视频](https://channel9.msdn.com/Events/CPP/CppCon-2016/CppCon-2016-Dietmar-Khl-Constant-Fun)与我的开发者故事链接。 –

回答

3

不打的语言。

的情况下,标签在C++ switch声明必须编译时评估常量表达式和C++标准库std::mapstd::unordered_map目前不提供。

使用ifelse块来代替。它甚至可能更快 - 特别是如果你选择了最佳订单。荷兰国际集团一个字符数组

switch(例如'+x';请注意单引号字符)经常讨论了作为对4个字符或更少的替代,但即使是不可移植的。

+1

呃,你说得对。如果你问我,唯一需要使用开关的地方就是枚举值。 – DeiDei

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 -constructible类型。不幸的是,std::string不是其中之一。

+0

Woah ...为什么我忽略那个?一方面,我说的是“constexpr”,另一方面我期望'switch-case'是预测性的。我想我现在应该睡觉了:O –

+2

Java允许顺便切换字符串。但是如果失去另一个C++的人到黑暗的一面,那将是一件耻辱。 – Bathsheba

+1

@Bathsheba:谢谢你救了我;) –

1

几个解决方案:

  1. 获取尽可能早地摆脱了弦。声明enum direction {posX, negX, posY, negY, posZ, negZ}并声明pointedto类型为direction而不是字符串。现在可以说case posY:这是编译时常量,但比case 2:更具可读性。更改hashmap<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}并找到一些巧妙的数学来转换弯曲并指向新的指向值。 注意:我在这里举例说明的值只是为了说明目的 - 只有在您确实需要优化此代码以获得性能时才应使用此路线。我提到了完整起见这条路线,但如果你决定去与它:)

编辑

采取不眠之夜不承担任何责任
  • 此:
  • #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生成,但我想在这里保持简单。
    相关问题