使用C++中的开关评估字符串

Ale*_*aro 47 c++

我想用开关评估一个字符串但是当我读取用户输入的字符串时会抛出以下错误.

#include<iostream>
using namespace std;

    int main() {
        string a;
        cin>>a;
        switch (string(a)) {
        case "Option 1":
            cout<<"It pressed number 1"<<endl;
            break;
        case "Option 2":
            cout<<"It pressed number 2"<<endl;
            break;
        case "Option 3":
            cout<<"It pressed number 3"<<endl;
            break;
        default:
            cout<<"She put no choice"<<endl;
            break;
        }
        return 0;
    }
Run Code Online (Sandbox Code Playgroud)

错误:从类型'std :: string {aka std :: basic_string}'无效转换为类型'int

Ser*_*hiy 78

如前所述,switch只能用于整数值.因此,您只需要将"case"值转换为整数.您可以使用c ++ 11中的constexpr来实现它,因此可以在编译时计算constexpr函数的一些调用.

类似的东西......

switch (str2int(s))
{
  case str2int("Value1"):
    break;
  case str2int("Value2"):
    break;
}
Run Code Online (Sandbox Code Playgroud)

str2int就像(从这里实现):

constexpr unsigned int str2int(const char* str, int h = 0)
{
    return !str[h] ? 5381 : (str2int(str, h+1) * 33) ^ str[h];
}
Run Code Online (Sandbox Code Playgroud)

另一个例子,下一个函数可以在编译时计算:

constexpr int factorial(int n)
{
    return n <= 1 ? 1 : (n * factorial(n-1));
}  

int f5{factorial(5)};
// Compiler will run factorial(5) 
// and f5 will be initialized by this value. 
// so programm instead of wasting time for running function, 
// just will put the precalculated constant to f5 
Run Code Online (Sandbox Code Playgroud)

  • 这正是我讨厌使用c ++的原因.它在很多方面都违反了最不惊讶的原则.这是其中之一. (12认同)
  • 小心只使用哈希来测试字符串相等性.例如,使用这个`str2int()`函数,`str2int("WS")== str2int("tP")`和`str2int("5g")== str2int("sa")`.请参阅http://dmytry.blogspot.com/2009/11/horrible-hashes.html由于您实际比较的字符串中的哈希冲突不太可能,我认为最好使用转换字符串的查找表到枚举(如mskfisher的回答所示). (12认同)
  • 编译器可能会这样做,也可能不这样做.如果你制作了`f5``constexpr`,就必须这样做. (2认同)

Ker*_* SB 17

switch语句只能被用于整数值,而不是为用户定义的类型的值.即使可能,您的输入操作也不起作用.

你可能想要这个:

#include <string>
#include <iostream>


std::string input;

if (!std::getline(std::cin, input)) { /* error, abort! */ }

if (input == "Option 1")
{
    // ... 
}
else if (input == "Option 2")
{ 
   // ...
}

// etc.
Run Code Online (Sandbox Code Playgroud)

  • @UnKnown:`>>`操作提取单个标记,用空格分隔,因此它永远不能检索值""选项1"`. (2认同)

msk*_*her 17

您可以将字符串映射到枚举值,然后打开枚举:

enum Options {
    Option_Invalid,
    Option1,
    Option2,
    //others...
};

Options resolveOption(string input);

//  ...later...

switch( resolveOption(input) )
{
    case Option1: {
        //...
        break;
    }
    case Option2: {
        //...
        break;
    }
    // handles Option_Invalid and any other missing/unmapped cases
    default: {
        //...
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

解析枚举可以实现为一系列if检查:

 Options resolveOption(std::string input) {
    if( input == "option1" ) return Option1;
    if( input == "option2" ) return Option2;
    //...
    return Option_Invalid;
 }
Run Code Online (Sandbox Code Playgroud)

或者地图查找:

 Options resolveOption(std::string input) {
    static const std::map<std::string, Option> optionStrings {
        { "option1", Option1 },
        { "option2", Option2 },
        //...
    };

    auto itr = optionStrings.find(input);
    if( itr != optionStrings.end() ) {
        return *itr;
    }
    return Option_Invalid; 
}
Run Code Online (Sandbox Code Playgroud)

  • 最后,通过这个解决方案,用 if/else 语句替换 switch 似乎确实更快。事实上,您可以在函数resolveOption 的第一个版本中执行此操作。 (2认同)

rmn*_*rmn 11

您只能对可转换为int的类型使用switch-case.

但是,您可以定义std::map<std::string, std::function> dispatcher并使用它dispatcher[str]()来达到相同的效果.

  • 您需要确保映射中存在一个函数,否则 [默认构造的 `std::function` 将抛出 `bad_function_call`](http://stackoverflow.com/a/7527115/44390)。您可以使用简单的 bool 检查来验证函数是否已初始化,例如 `auto &amp;fn = dispatcher[str]; 如果( fn ) { fn(); }` (2认同)