编译时字符串哈希化

12
我需要使用字符串作为ID来获取一些对象。在运行时实现这一点,并且可以正常工作。但是由于明显的原因,这使得静态类型检查变得不可能。
我已经在谷歌上搜索了计算编译时字符串哈希值的算法:使用Boost.MPL进行C ++编译时字符串哈希
这似乎是解决我的问题的完美方案,除了必须将算法所需的字符串分成4个字符或逐个字符拆分的明显原因。
即,我将不得不以这种方式编写而不是通常的当前ID记录方式:
hash_cstring<boost::mpl::string<'obje', 'ct.m', 'etho', 'd'>>::value

这绝对是不能使用的。

问题是,如何正确传递像"object.method"这样的字符串到该算法中?

谢谢大家。


1
你能否使用带有静态字符串的结构体来代替直接使用字符串?或者使用宏来生成它们? - Anycorn
1
@aaa:宏不会分割标记,它们可以将它们串联或连接起来,但不能将它们分开。 - Matthieu M.
@Matt 宏用于生成带有名称和静态字符串的结构体。例如 #define str(n) struct n { ... } - Anycorn
有没有考虑使用gperf并用类型包装结果? - CoreyStup
4个回答

9

使用gcc-4.6的解决方案:

#include <iostream>
template<size_t N, size_t I=0>
struct hash_calc {
    static constexpr size_t apply (const char (&s)[N]) {
       return  (hash_calc<N, I+1>::apply(s) ^ s[I]) * 16777619u;
    };
};

template<size_t N>
struct hash_calc<N,N> {
    static constexpr size_t apply (const char (&s)[N]) {
       return  2166136261u;
    };
};

template<size_t N>
constexpr size_t hash ( const char (&s)[N] ) {
    return hash_calc<N>::apply(s);
}

int main() {
   char a[] = "12345678";
   std::cout << std::hex << hash(a) << std::endl;
   std::cout << std::hex << hash("12345678") << std::endl;
}

http://liveworkspace.org/code/DPObf

我很高兴!


你是否真的能够在没有递归错误的情况下使用gcc 4.6编译这个程序? - Damon
有趣的是,我的gcc-4.6.1(MingW-TDM)用所述错误拒绝了那段代码(这就是我问的原因)。 - Damon
在 'static constexpr size_t hash_calc<N, N>::apply(const char (&)[N]) [with unsigned int N = 10u, size_t = unsigned int]' 的实例化中: 从 'static constexpr size_t hash_calc<N, I>::apply(const char (&)[N]) [with unsigned int N = 10u, unsigned int I = 1u, size_t = unsigned int]' 递归实例化 从 'static constexpr size_t hash_calc<N, I>::apply(const char (&)[N]) [with unsigned int N = 10u, unsigned int I = 0u, size_t = unsigned int]' 实例化 从 'constexpr size_t hash(const char (&)[N]) [with unsigned int N = 10u, size_t = unsigned int]' 实例化。 - Damon
我不确定TDM构建。我使用这些构建:http://code.google.com/p/mingw-builds/ - niXman

5

我不知道有没有用预处理器或模板实现这个功能的方法。我猜想你最好创建一个单独的预编译步骤(比如使用perl等),从一组源语句中生成hash_cstring语句。这样,当你添加新的语句时,就不必手动拆分字符串了,而且生成过程是完全自动化和可重复的。


1

如果有人感兴趣,我会在这里详细介绍如何使用C++11的constexpr函数和可变参数模板创建Murmur3_32的编译时哈希。

http://roartindon.blogspot.sg/2014/10/compile-time-murmur-hash-in-c.html

我看到的大多数示例都涉及基于一次消耗一个字符的散列。 Murmur3_32哈希算法更有趣,因为它每次消耗4个字符,并需要一些特殊情况代码来处理剩余的0、1、2或3个字节。

1

模板可以使用任何外部符号进行实例化,因此这应该按预期工作:

external char const* object_method = "object.method";
... = hash_cstring<object_method>::value;

(考虑到模板 hash_cstring<> 能够处理指针值。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接