您好, 我需要在switch case中使用一个字符串。到目前为止,我的解决方案是用哈希函数计算字符串的哈希值。问题是我必须手动预先计算字符串的所有哈希值。有更好的方法吗?
h=_myhash (mystring);
switch (h)
{
case 66452:
.......
case 1342537:
........
}
答案 0 :(得分:36)
只需使用if() { } else if () { }
链。使用哈希值将成为维护的噩梦。 switch
旨在成为一个低级语句,不适合字符串比较。
答案 1 :(得分:14)
您可以使用标准集合将字符串映射到函数指针;找到匹配项时执行该功能。
编辑:使用我在评论中给出链接的文章中的示例,您可以声明一个函数指针类型:
typedef void (*funcPointer)(int);
并创建多个与签名匹配的函数:
void String1Action(int arg);
void String2Action(int arg);
地图为std::string
至funcPointer
:
std::map<std::string, funcPointer> stringFunctionMap;
然后添加字符串和函数指针:
stringFunctionMap.add("string1", &String1Action);
我没有测试过我刚刚发布的任何代码,但它不在我的脑海中:)
答案 2 :(得分:6)
通常,您将使用散列表和函数对象,两者都在Boost,TR1和C ++ 0x中可用。
void func1() {
}
std::unordered_map<std::string, std::function<void()>> hash_map;
hash_map["Value1"] = &func1;
// .... etc
hash_map[mystring]();
这在运行时稍微增加了一些,但是可维护的数量要多出几倍。散列表提供O(1)插入,查找等,这使得它们与汇编式跳转表具有相同的复杂性。
答案 3 :(得分:2)
最好的方法是使用源生成,以便您可以使用
if (hash(str) == HASH("some string") ..
在主源中,预构建步骤会将HASH(const char*)
表达式转换为整数值。
答案 4 :(得分:2)
Ruslik建议使用源代码对我来说似乎是一件好事。但是,我不会使用“主要”和“生成”源文件的概念。我宁愿有一个代码几乎与你的代码相同的文件:
h=_myhash (mystring);
switch (h)
{
case 66452: // = hash("Vasia")
.......
case 1342537: // = hash("Petya")
........
}
接下来我要做的是,我会写一个简单的脚本。 Perl对于这类东西很有用,但是如果你不想使用任何其他语言,那么即使用C / C ++编写一个简单的程序也没有什么能阻止你。此脚本或程序将获取源文件,逐行读取,查找所有case NUMBERS: // = hash("SOMESTRING")
行(在此处使用正则表达式),将NUMBERS替换为实际哈希值,并将修改后的源写入临时文件。最后,它将备份源文件并将其替换为临时文件。如果您不希望源文件每次都有新的时间戳,程序可以检查是否实际更改了某些内容,如果没有,则跳过文件替换。
最后要做的是将此脚本集成到所使用的构建系统中,这样您就不会在构建项目之前意外忘记启动它。
答案 5 :(得分:1)
您可以使用该字符串索引到函数指针的哈希表中。
编辑:glib有一个哈希表实现,它支持字符串作为键和任意指针作为值:http://library.gnome.org/devel/glib/stable/glib-Hash-Tables.html
答案 6 :(得分:1)
您可以创建一个哈希表。键可以是字符串,值可以是整数。将值作为常量设置为整数,然后使用switch
检查它们。
答案 7 :(得分:1)
您可以使用枚举和地图,因此您的字符串将成为键,枚举值是该键的值。
答案 8 :(得分:1)
如果您正在执行并且不希望每次都查看所有if
子句,如果有很多或需要散列值,您可以通过帮助向函数发送一些额外信息enum
或仅在您的结构中添加enum
类型。
答案 9 :(得分:1)
你的问题没有很好的解决方案,所以这里有一个好的解决方案; - )
它在断言被禁用时保持你的效率,当断言被启用时,它会在哈希值错误时引发一个断言错误。
我怀疑D编程语言可以在编译期间计算哈希值,因此无需显式写下哈希值。
template <std::size_t h>
struct prehash
{
const your_string_type str;
static const std::size_t hash_value = h;
pre_hash(const your_string_type& s) : str(s)
{
assert(_myhash(s) == hash_value);
}
};
/* ... */
std::size_t h = _myhash(mystring);
static prehash<66452> first_label = "label1";
switch (h) {
case first_label.hash_value:
// ...
;
}
顺便说一句,考虑从_ myhash()的声明中删除初始下划线(抱歉,stackoverflow强制我在_和myhash之间插入一个空格)。 C ++实现可以自由地实现名称以下划线和大写字母开头的宏(Herb Sutter的“Exceptional C ++ Style”第36项),所以如果你养成了让名字开始下划线的习惯,那么美好的一天当您为符号指定一个以下划线和大写字母开头的名称时,可能会出现,其中实现已定义了一个具有相同名称的宏。