Add case string matching to C++ switch

为C++的switch添加case的字符串匹配

The switch in the C++ standard cannot implement string case matching, but we often have this need, so let’s implement it.

The desired result is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
switch("123"){
case "123":{
// ...
break;
}
case "456":{
// ...
break;
}
// ...
default:{
// ...
break;
}
}

Directly matching strings is not possible; in C++, case can only match a constant expression of the same type as the type of condition after conversions and integral promotions, so here I need to convert the string to a literal integer for case matching.

To convert a string to a number, we can use HASH (Wikipedia - hash function) to compute it, and here I am using the hash algorithm from Chromium to calculate the hash value of string strings (Chromium - string_piece.h).

The hash calculation code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Hashing ---------------------------------------------------------------------

// We provide appropriate hash functions so StringPiece and StringPiece16 can
// be used as keys in hash sets and maps.

// This hash function is copied from base/strings/string16.h. We don't use the
// ones already defined for string and string16 directly because it would
// require the string constructors to be called, which we don't want.
#define HASH_STRING_PIECE(StringPieceType, string_piece) \
std::size_t result = 0; \
for (StringPieceType::const_iterator i = string_piece.begin(); \
i != string_piece.end(); ++i) \
result = (result * 131) + *i; \
return result;

struct StringPieceHash {
std::size_t operator()(const StringPiece& sp) const {
HASH_STRING_PIECE(StringPiece, sp);
}
};
struct StringPiece16Hash {
std::size_t operator()(const StringPiece16& sp16) const {
HASH_STRING_PIECE(StringPiece16, sp16);
}
};

We need to use the HASH_STRING_PIECE macro definition here.

With C++11 features, we can define a constexpr function (for details, see the end-of-article links) and call this constexpr function at the case label of the switch.

Here, I wrote a recursive function to implement the above hash calculation:

1
2
3
constexpr size_t HASH_STRING_PIECE(const char *string_piece,size_t hashNum=0){
return *string_piece?HASH_STRING_PIECE(string_piece+1,(hashNum*131)+*string_piece):hashNum;
}

At this point, we can write in the switch like this:

1
2
3
4
5
6
7
8
9
10
switch(HASH_STRING_PIECE("123")){
case HASH_STRING_PIECE("123"):{
cout<<"123"<<endl;
break;
}
case HASH_STRING_PIECE("456"):{
cout<<"456"<<endl;
break;
}
}

For convenience, we can overload the "" operator to facilitate its use instead of calling the HASH_STRING_PIECE function directly every time, also to better conform to case usage specifications.

1
2
3
constexpr size_t operator "" _HASH(const char *string_pice,size_t){
return HASH_STRING_PIECE(string_pice);
}

Then it can be used like this:

1
2
3
4
5
6
7
8
9
10
switch(HASH_STRING_PIECE("123")){
case "123"_HASH:{
cout<<"123"<<endl;
break;
}
case "456"_HASH:{
cout<<"456"<<endl;
break;
}
}

If you want to directly use the standard library string, you can write a function like this:

1
2
3
4
size_t CALC_STRING_HASH(const string& str){
// Retrieve the string value of the string object and pass it to HASH_STRING_PIECE to calculate, and the return value is the HASH value of that string
return HASH_STRING_PIECE(str.c_str());
}

Then, when directly passing a string object, you can call the CALC_STRING_HASH function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main(int argc,char* argv[])
{
cout<<"switch list in \"123\"/\"456\"/\"789\",Please input:";
string input;
cin>>input;
switch(CALC_STRING_HASH(input)){
case "123"_HASH:{
cout<<"the case is 123"<<endl;
break;
}
case "456"_HASH:{
cout<<"the case is 456"<<endl;
break;
}
case "789"_HASH:{
cout<<"the case is 789"<<endl;
break;
}
default:
cout<<"Not found"<<endl;
break;

}
return 0;
}

cppreference - constexpr
C++11FAQ - constexpr

The article is finished. If you have any questions, please comment and communicate.

Scan the QR code on WeChat and follow me.

Title:Add case string matching to C++ switch
Author:LIPENGZHA
Publish Date:2016/09/24 22:43
Word Count:1.2k Words
Link:https://en.imzlp.com/posts/1494/
License: CC BY-NC-SA 4.0
Reprinting of the full article is prohibited.
Your donation will encourage me to keep creating!