编译下面的代码会得到错误消息:type illegal。

int main()
{
    // Compilation error - switch expression of type illegal
    switch(std::string("raj"))
    {
    case"sda":
    }
}

你不能在switch或case中使用字符串。为什么?是否有任何解决方案可以很好地支持类似于打开字符串的逻辑?


当前回答

使用尽可能简单的容器添加一个变体(不需要一个有序的映射)…我不会使用枚举——只是把容器定义放在切换之前,这样就很容易看出哪个数字代表哪个情况。

这将在unordered_map中进行哈希查找,并使用相关的int来驱动switch语句。应该很快。注意,这里使用的是at而不是[],因为我已经将该容器设置为const。使用[]可能是危险的——如果字符串不在映射中,您将创建一个新的映射,并可能以未定义的结果或不断增长的映射结束。

注意,如果字符串不在映射中,at()函数将抛出异常。因此,您可能希望首先使用count()进行测试。

const static std::unordered_map<std::string,int> string_to_case{
   {"raj",1},
   {"ben",2}
};
switch(string_to_case.at("raj")) {
  case 1: // this is the "raj" case
       break;
  case 2: // this is the "ben" case
       break;


}

测试未定义字符串的版本如下:

const static std::unordered_map<std::string,int> string_to_case{
   {"raj",1},
   {"ben",2}
};
// in C++20, you can replace .count with .contains
switch(string_to_case.count("raj") ? string_to_case.at("raj") : 0) {
  case 1: // this is the "raj" case
       break;
  case 2: // this is the "ben" case
       break;
  case 0: //this is for the undefined case

}

其他回答

问题是,由于优化的原因,c++中的switch语句只能用于基本类型,你只能将它们与编译时常量进行比较。

这种限制的原因可能是编译器能够应用某种形式的优化,将代码编译为一个cmp指令和一个goto,其中地址是根据运行时参数的值计算的。由于分支和循环在现代cpu上不能很好地发挥作用,因此这可能是一个重要的优化。

要解决这个问题,恐怕你将不得不求助于if语句。

在c++中,你只能在int和char上使用switch语句

我认为原因是在C语言中字符串不是基本类型,就像tomjen说的,把字符串看作一个char数组,所以你不能做这样的事情:

switch (char[]) { // ...
switch (int[]) { // ...

这是因为c++将开关转换为跳转表。它对输入数据执行简单的操作,并在不进行比较的情况下跳转到适当的地址。因为字符串不是一个数字,而是一个数字数组,所以c++不能从它创建一个跳转表。

movf    INDEX,W     ; move the index value into the W (working) register from memory
addwf   PCL,F       ; add it to the program counter. each PIC instruction is one byte
                    ; so there is no need to perform any multiplication. 
                    ; Most architectures will transform the index in some way before 
                    ; adding it to the program counter

table                   ; the branch table begins here with this label
    goto    index_zero  ; each of these goto instructions is an unconditional branch
    goto    index_one   ; of code
    goto    index_two
    goto    index_three

index_zero
    ; code is added here to perform whatever action is required when INDEX = zero
    return

index_one
...

(代码来自维基百科https://en.wikipedia.org/wiki/Branch_table)

C++

Constexpr哈希函数:

constexpr unsigned int hash(const char *s, int off = 0) {                        
    return !s[off] ? 5381 : (hash(s, off+1)*33) ^ s[off];                           
}                                                                                

switch( hash(str) ){
case hash("one") : // do something
case hash("two") : // do something
}

更新:

上面的例子是c++ 11。这里的constexpr函数必须是单语句。这在接下来的c++版本中得到了放宽。

在c++ 14和c++ 17中,你可以使用以下哈希函数:

constexpr uint32_t hash(const char* data, size_t const size) noexcept{
    uint32_t hash = 5381;

    for(const char *c = data; c < data + size; ++c)
        hash = ((hash << 5) + hash) + (unsigned char) *c;

    return hash;
}

c++ 17也有std::string_view,所以你可以用它来代替const char *。

在c++ 20中,您可以尝试使用consteval。