Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么switch语句不能应用于字符串?_C++_String_Switch Statement - Fatal编程技术网

C++ 为什么switch语句不能应用于字符串?

C++ 为什么switch语句不能应用于字符串?,c++,string,switch-statement,C++,String,Switch Statement,编译以下代码并得到错误类型非法 int main() { // Compilation error - switch expression of type illegal switch(std::string("raj")) { case"sda": } } 不能在开关或大小写中使用字符串。为什么?是否有任何解决方案能很好地支持类似于切换字符串的逻辑?在C++中, 只能在int上使用一个开关语句,而C++中的char 和c开关只对整数类型进行工作。改用i

编译以下代码并得到错误
类型非法

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

不能在
开关
大小写
中使用字符串。为什么?是否有任何解决方案能很好地支持类似于切换字符串的逻辑?在C++中,

只能在int上使用一个开关语句,而C++中的char

和c开关只对整数类型进行工作。改用if-else梯形图。C++显然可以实现一些字符串的SWICH语句——我想没有人认为它是值得的,我同意。

< P>问题是,由于优化的原因,C++中的转换语句对原始类型的任何东西都不起作用,而只能将它们与编译时常数进行比较。 可能限制的原因是编译器能够应用某种形式的优化,将代码编译到一条cmp指令和一个goto,其中地址是在运行时根据参数的值计算的。由于分支和循环不能很好地与现代CPU配合使用,因此这可能是一个重要的优化


要解决这个问题,恐怕您必须使用if语句。

您不能在switch case中使用string。只允许使用int&char。相反,您可以尝试使用enum表示字符串,并在switch case块中使用它,如

enum MyString(raj,taj,aaj);

在swich case语句中使用它。

原因与类型系统有关。C/C++实际上不支持字符串作为类型。它确实支持常量字符数组的概念,但它并没有真正完全理解字符串的概念

为了生成switch语句的代码,编译器必须理解两个值相等意味着什么。对于int和enum之类的项,这是一个简单的位比较。但是编译器应该如何比较两个字符串值呢?区分大小写、不区分大小写、区分区域性等。。。如果不完全了解字符串,则无法准确回答此问题


此外,C/C++switch语句通常按以下方式生成。为字符串样式开关生成分支表几乎不那么容易

我认为原因在于,在C中,字符串不是基本类型,正如tomjen所说,将字符串视为字符数组,因此不能执行以下操作:

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

如前所述,编译器喜欢构建查找表,尽可能将
语句切换到接近O(1)的时间。结合C++语言没有字符串类型的事实,<>代码> STD::String 是标准库的一部分,标准库本身不是语言的一部分。
我将提供一个你可能想考虑的替代方案,过去我用它来达到很好的效果。切换使用字符串作为输入的哈希函数的结果,而不是切换字符串本身。如果您使用的是一组预先确定的字符串,那么您的代码几乎与切换字符串一样清晰:

enum string_code {
    eFred,
    eBarney,
    eWilma,
    eBetty,
    ...
};

string_code hashit (std::string const& inString) {
    if (inString == "Fred") return eFred;
    if (inString == "Barney") return eBarney;
    ...
}

void foo() {
    switch (hashit(stringValue)) {
    case eFred:
        ...
    case eBarney:
        ...
    }
}

有一系列明显的优化,它们基本上遵循了C编译器对switch语句所做的操作。。。有趣的是,C++字符串中的

< P>不是第一类公民。字符串操作通过标准库完成。我想,这就是原因。此外,C++使用分支表优化来优化交换机实例语句。看看这个链接


开关仅适用于整型(int、char、bool等)。为什么不使用映射将字符串与数字配对,然后将该数字与开关一起使用?

C++11的更新显然不是上面的@MarmouCorp,而是

使用两个映射在字符串和类enum之间进行转换(比普通enum更好,因为它的值在它的范围内,并且反向查找漂亮的错误消息)

通过编译器对初始值设定项列表的支持,可以在codeguru代码中使用static,这意味着VS 2013 plus。GCC4.8.1对它没问题,不确定它能兼容多久

/// <summary>
/// Enum for String values we want to switch on
/// </summary>
enum class TestType
{
    SetType,
    GetType
};

/// <summary>
/// Map from strings to enum values
/// </summary>
std::map<std::string, TestType> MnCTest::s_mapStringToTestType =
{
    { "setType", TestType::SetType },
    { "getType", TestType::GetType }
};

/// <summary>
/// Map from enum values to strings
/// </summary>
std::map<TestType, std::string> MnCTest::s_mapTestTypeToString
{
    {TestType::SetType, "setType"}, 
    {TestType::GetType, "getType"}, 
};

<代码> CUT

这是因为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
...

(来自wikipedia的代码)

使用最简单的容器添加变体(无需有序映射)。。。我不想麻烦使用枚举——只需将容器定义放在开关的前面,这样就可以很容易地看到哪个数字代表哪种情况

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

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

const static std::无序映射字符串到大小写{
{“raj”,1},
{“本”,2}
};
开关(字符串_到_case.at(“raj”)){
案例1://这是“raj”案例
打破
案例2://这是“本”案
打破
}
对未定义字符串进行测试的版本如下:

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

}
const static std::无序映射字符串到大小写{
{“raj”,1},
{“本”,2}
};
//在C++20中,可以将.count替换为.contains
开关(字符串到大小写计数(“raj”)?字符串到大小写计数(“raj”):0){
案例1://这是“raj”案例
打破
案例2://这是“本”案
打破
案例0://这是针对未定义的案例
}

在许多情况下,您可以通过从字符串中提取第一个字符并打开它来节省额外的工作。可能最终不得不在charat(1)上执行嵌套切换,如果
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
...
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

}
std::string name = "Alice";

std::string gender = "boy";
std::string role;

SWITCH(name)
  CASE("Alice")   FALL
  CASE("Carol")   gender = "girl"; FALL
  CASE("Bob")     FALL
  CASE("Dave")    role   = "participant"; BREAK
  CASE("Mallory") FALL
  CASE("Trudy")   role   = "attacker";    BREAK
  CASE("Peggy")   gender = "girl"; FALL
  CASE("Victor")  role   = "verifier";    BREAK
  DEFAULT         role   = "other";
END

// the role will be: "participant"
// the gender will be: "girl"
#include <functional>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>

int main() {
    int result;
    const std::unordered_map<std::string,std::function<void()>> m{
        {"one",   [&](){ result = 1; }},
        {"two",   [&](){ result = 2; }},
        {"three", [&](){ result = 3; }},
    };
    const auto end = m.end();
    std::vector<std::string> strings{"one", "two", "three", "foobar"};
    for (const auto& s : strings) {
        auto it = m.find(s);
        if (it != end) {
            it->second();
        } else {
            result = -1;
        }
        std::cout << s << " " << result << std::endl;
    }
}
one 1
two 2
three 3
foobar -1
#include <functional>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>

class RangeSwitch {
public:
    void method(std::string key, int &result) {
        static const std::unordered_map<std::string,std::function<void(int&)>> m{
            {"one",   [](int& result){ result = 1; }},
            {"two",   [](int& result){ result = 2; }},
            {"three", [](int& result){ result = 3; }},
        };
        static const auto end = m.end();
        auto it = m.find(key);
        if (it != end) {
            it->second(result);
        } else {
            result = -1;
        }
    }
};

int main() {
    RangeSwitch rangeSwitch;
    int result;
    std::vector<std::string> strings{"one", "two", "three", "foobar"};
    for (const auto& s : strings) {
        rangeSwitch.method(s, result);
        std::cout << s << " " << result << std::endl;
    }
}
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
}
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;
}
#include <uberswitch/uberswitch.hpp>

int main()
{
    uberswitch (std::string("raj"))
    {
        case ("sda"): /* ... */ break;  //notice the parenthesis around the value.
    }
}
constexpr const char* arr[] = { "bar", "foo" };
constexpr int index(const char* str) { /*...*/ }

do_something(std::string str)
{
    switch(quick_index(str))
    {
        case index("bar"):
            // ...
            break;

        case index("foo"):
            // ...
            break;

        case -1:
        default:
            // ...
            break;
    }
#include <iostream>
#include <algorithm>
#include <unordered_map>

constexpr const char* arr[] = { "bar", "foo", "foobar" };

constexpr int cmp(const char* str1, const char* str2)
{
    return *str1 == *str2 && (!*str1 || cmp(str1+1, str2+1));
}

constexpr int index(const char* str, int pos=0)
{
    return pos == sizeof(arr)/sizeof(arr[0]) ? -1 : cmp(str, arr[pos]) ? pos : index(str,pos+1);
}

int main()
{
    // initialize hash table once
    std::unordered_map<std::string,int> lookup;
    int i = 0;
    for(auto s : arr) lookup[s] = i++;
    auto quick_index = [&](std::string& s)
        { auto it = lookup.find(s); return it == lookup.end() ? -1 : it->second; };
    
    // usage in code
    std::string str = "bar";
    
    switch(quick_index(str))
    {
        case index("bar"):
            std::cout << "bartender" << std::endl;
            break;

        case index("foo"):
            std::cout << "fighter" << std::endl;
            break;

        case index("foobar"):
            std::cout << "fighter bartender" << std::endl;
            break;
            
        case -1:
        default:
            std::cout << "moo" << std::endl;
            break;
    }
}