编译下面的代码会得到错误消息: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中使用字符串。为什么?是否有任何解决方案可以很好地支持类似于打开字符串的逻辑?
当前回答
这是我前段时间提出的一个解决方案,它完全遵守所请求的语法。
#include <uberswitch/uberswitch.hpp>
int main()
{
uswitch (std::string("raj"))
{
ucase ("sda"): /* ... */ break; //notice the parenthesis around the value.
}
}
代码如下:https://github.com/falemagn/uberswitch
其他回答
开关问题的更实用的解决方案:
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)
{
// ...
}
}
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;
}
}
这是因为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)
在许多情况下,您可以通过从字符串中提取第一个字符并打开它来进行额外的工作。如果您的case以相同的值开始,可能最终必须在charat(1)上进行嵌套切换。任何阅读您的代码的人都会喜欢一个提示,因为大多数人会只使用if-else-if
您可以将字符串放在数组中,并在编译时使用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;
}
}