yes*_*aaj 208 c++ string switch-statement
编译以下代码并得到错误type illegal.
int main()
{
// Compilation error - switch expression of type illegal
switch(std::string("raj"))
{
case"sda":
}
}
Run Code Online (Sandbox Code Playgroud)
你不能在任何一个switch或中使用字符串case.为什么?是否有任何解决方案可以很好地支持类似于切换字符串的逻辑?
Jar*_*Par 176
之所以与类型系统有关.C/C++并不真正支持字符串作为一种类型.它确实支持常量char数组的想法,但它并不完全理解字符串的概念.
为了生成switch语句的代码,编译器必须理解两个值相等的含义.对于像int和enums这样的项目,这是一个微不足道的比较.但是编译器应该如何比较2个字符串值呢?区分大小写,不敏感,文化意识等...如果没有完全意识到字符串,则无法准确回答.
此外,C/C++ switch语句通常作为分支表生成.为字符串样式开关生成分支表并不容易.
D.S*_*ley 54
如前所述,编译器喜欢构建查找表,switch尽可能将语句优化到接近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:
...
}
}
Run Code Online (Sandbox Code Playgroud)
有一堆显而易见的优化几乎遵循C编译器对switch语句的处理......有趣的是如何发生.
Mar*_*orp 31
您只能使用switch,例如int,char和enum.像你想要的那样,最简单的解决方案是使用枚举.
#include <map>
#include <string>
#include <iostream.h>
// Value-Defintions of the different String values
static enum StringValue { evNotDefined,
evStringValue1,
evStringValue2,
evStringValue3,
evEnd };
// Map to associate the strings with the enum values
static std::map<std::string, StringValue> s_mapStringValues;
// User input
static char szInput[_MAX_PATH];
// Intialization
static void Initialize();
int main(int argc, char* argv[])
{
// Init the string map
Initialize();
// Loop until the user stops the program
while(1)
{
// Get the user's input
cout << "Please enter a string (end to terminate): ";
cout.flush();
cin.getline(szInput, _MAX_PATH);
// Switch on the value
switch(s_mapStringValues[szInput])
{
case evStringValue1:
cout << "Detected the first valid string." << endl;
break;
case evStringValue2:
cout << "Detected the second valid string." << endl;
break;
case evStringValue3:
cout << "Detected the third valid string." << endl;
break;
case evEnd:
cout << "Detected program end command. "
<< "Programm will be stopped." << endl;
return(0);
default:
cout << "'" << szInput
<< "' is an invalid string. s_mapStringValues now contains "
<< s_mapStringValues.size()
<< " entries." << endl;
break;
}
}
return 0;
}
void Initialize()
{
s_mapStringValues["First Value"] = evStringValue1;
s_mapStringValues["Second Value"] = evStringValue2;
s_mapStringValues["Third Value"] = evStringValue3;
s_mapStringValues["end"] = evEnd;
cout << "s_mapStringValues contains "
<< s_mapStringValues.size()
<< " entries." << endl;
}
Run Code Online (Sandbox Code Playgroud)
Dir*_*ter 14
上面显然不是@MarmouCorp的C++ 11更新,但http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4067/Switch-on-Strings-in-C.htm
使用两个映射在字符串和类枚举之间进行转换(优于普通枚举,因为它的值在其中作用域,反向查找好的错误消息).
在编译器支持初始化列表时,可以在codeguru代码中使用static,这意味着VS 2013 plus.gcc 4.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"},
};
Run Code Online (Sandbox Code Playgroud)
...
std::string someString = "setType";
TestType testType = s_mapStringToTestType[someString];
switch (testType)
{
case TestType::SetType:
break;
case TestType::GetType:
break;
default:
LogError("Unknown TestType ", s_mapTestTypeToString[testType]);
}
Run Code Online (Sandbox Code Playgroud)
Nic*_*ick 14
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
}
Run Code Online (Sandbox Code Playgroud)
tom*_*jen 11
问题在于,出于优化的原因,C++中的switch语句不能用于任何原始类型,并且只能将它们与编译时常量进行比较.
据推测,限制的原因是编译器能够应用某种形式的优化,将代码编译为一个cmp指令,以及根据运行时参数的值计算地址的goto.由于分支和循环不能很好地与现代CPU配合使用,因此这可能是一项重要的优化.
为了解决这个问题,我恐怕你不得不求助于if声明.
要使用最简单的容器添加变体(不需要有序映射)......我不会打扰枚举 - 只需将容器定义放在 switch 之前,这样就很容易看到哪个数字代表这种情况下。
这会在 中进行散列查找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;
}
Run Code Online (Sandbox Code Playgroud)
对未定义字符串进行测试的版本如下:
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
}
Run Code Online (Sandbox Code Playgroud)
std::map + C++ 11没有枚举的lambda模式
unordered_map潜在的摊销O(1): 在C++中使用HashMap的最佳方法是什么?
#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;
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
one 1
two 2
three 3
foobar -1
Run Code Online (Sandbox Code Playgroud)
用法里面的方法 static
要在类中有效地使用此模式,请静态初始化lambda映射,否则O(n)每次都要从头开始构建它.
在这里我们可以摒弃方法变量的{}初始化static:类方法中的静态变量,但我们也可以使用C++中的静态构造函数描述的方法?我需要初始化私有静态对象
有必要将lambda上下文捕获[&]转换为参数,或者本来是未定义的:const static auto lambda与参考捕获一起使用
产生与上面相同的输出的示例:
#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;
}
}
Run Code Online (Sandbox Code Playgroud)
为什么不?您可以使用具有等效语法和相同语义的switch实现.该C语言根本没有对象和字符串对象,但字符串C是指针引用的空终止字符串.该C++语言有可能为对象比较或检查对象的等式制作重载函数.由于C作为C++具有足够的灵活性,以对字符串这样的开关C
语言和支持comparaison或检查平等对任何类型的对象C++语言.现代C++11允许这种开关实现足够有效.
你的代码将是这样的:
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"
Run Code Online (Sandbox Code Playgroud)
例如,可以使用更复杂的类型std::pairs或支持相等操作的任何结构或类(或快速模式的同化).
Sintax与语言切换的区别在于
对于C++97使用线性搜索的语言.对于C++11更现代的可能使用quick模式wuth树搜索,其中CASE 中的return语句变得不被允许.在C存在语言实现,其中char*的类型和0结尾的字符串comparisions使用.
| 归档时间: |
|
| 查看次数: |
332179 次 |
| 最近记录: |