编译下面的代码会得到错误消息:type illegal。
int main()
{
// Compilation error - switch expression of type illegal
switch(std::string("raj"))
{
case"sda":
}
}
你不能在switch或case中使用字符串。为什么?是否有任何解决方案可以很好地支持类似于打开字符串的逻辑?
编译下面的代码会得到错误消息:type illegal。
int main()
{
// Compilation error - switch expression of type illegal
switch(std::string("raj"))
{
case"sda":
}
}
你不能在switch或case中使用字符串。为什么?是否有任何解决方案可以很好地支持类似于打开字符串的逻辑?
当前回答
在c++中,字符串不是一等公民。字符串操作是通过标准库完成的。我想,这就是原因。另外,c++使用分支表优化来优化开关case语句。看看这个链接。
http://en.wikipedia.org/wiki/Switch_statement
其他回答
Why not? You can use switch implementation with equivalent syntax and same semantics. The C language does not have objects and strings objects at all, but strings in C is null terminated strings referenced by pointer. The C++ language have possibility to make overload functions for objects comparision or checking objects equalities. As C as C++ is enough flexible to have such switch for strings for C language and for objects of any type that support comparaison or check equality for C++ language. And modern C++11 allow to have this switch implementation enough effective.
你的代码是这样的:
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"
可以使用更复杂的类型,例如std::pairs或任何支持相等操作(或快速模式的比较)的结构或类。
特性
支持比较或检验相等性的任何类型的数据 构建级联嵌套开关语句的可能性。 打破case语句的可能性 使用非常量大小写表达式的可能性 可以通过树搜索启用快速静态/动态模式(适用于c++ 11)
汉译语的差异在于语言的转换
大写的字 CASE语句需要括号 语句末尾不允许使用分号 冒号':' at CASE语句不被允许 在CASE语句的末尾需要一个BREAK或FALL关键字
对于c++ 97语言采用线性搜索。 对于c++ 11和更现代的可能使用快速模式wuth树搜索,其中CASE中的return语句变得不允许。 C语言实现中使用char*类型和以零结尾的字符串比较。
阅读更多关于这个开关实现的信息。
开关问题的更实用的解决方案:
class APIHandlerImpl
{
// define map of "cases"
std::map<string, std::function<void(server*, websocketpp::connection_hdl, string)>> in_events;
public:
APIHandlerImpl()
{
// bind handler method in constructor
in_events["/hello"] = std::bind(&APIHandlerImpl::handleHello, this, _1, _2, _3);
in_events["/bye"] = std::bind(&APIHandlerImpl::handleBye, this, _1, _2, _3);
}
void onEvent(string event = "/hello", string data = "{}")
{
// execute event based on incomming event
in_events[event](s, hdl, data);
}
void APIHandlerImpl::handleHello(server* s, websocketpp::connection_hdl hdl, string data)
{
// ...
}
void APIHandlerImpl::handleBye(server* s, websocketpp::connection_hdl hdl, string data)
{
// ...
}
}
您可以将字符串放在数组中,并在编译时使用constexpr将它们转换为索引。
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;
}
对于quick_index,它不一定是constexpr,你可以使用unordered_map在运行时做O(1)。(或者对数组进行排序并使用二进制搜索,参见这里的示例。)
下面是c++ 11的完整示例,使用了一个简单的自定义constexpr字符串比较器。重复的case和不在数组中的case (index给出-1)将在编译时被检测到。遗漏的病例显然没有被发现。后来的c++版本拥有更灵活的constexpr表达式,允许编写更简单的代码。
#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;
}
}
开关仅适用于整型(int, char, bool等)。为什么不使用映射将字符串与数字配对,然后将该数字与开关使用呢?
std::map + c++ 11没有枚举的lambdas模式
潜在的平摊O(1)的unordered_map:在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;
}
}
输出:
one 1
two 2
three 3
foobar -1
在静态方法中使用
要在类中有效地使用这种模式,可以静态地初始化lambda映射,否则每次从头构建时都要付出O(n)。
在这里,我们可以摆脱静态方法变量的{}初始化:类方法中的静态变量,但我们也可以使用在:c++中的静态构造函数?我需要初始化私有静态对象
必须将lambda上下文捕获[&]转换为参数,否则将未定义:const static auto lambda与capture by reference一起使用
示例,产生与上面相同的输出:
#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;
}
}