[英]Is it possible to get hash values as compile-time constants?
我以為我會嘗試通過散列來選擇不同的選項作為字符串,但這不起作用:
#include <type_traits>
#include <string>
inline void selectMenuOptionString(const std::string& str)
{
switch (std::hash<std::string>()(str))
{
case std::hash<std::string>()(std::string("Selection one")) : break;
// Expression must have a constant value
}
}
inline void selectMenuOptionString2(const std::string& str)
{
size_t selectionOneHash = std::hash<std::string>()(std::string("Selection one"));
switch (std::hash<std::string>()(str))
{
case selectionOneHash: // Expression must have a constant value
// The variable of selectionOneHash cannot be used as a constant
}
constexpr size_t hash = std::hash<int>()(6); // Expression must have a constant value
}
似乎我無法在編譯時獲取哈希值。 根據我的閱讀,每次不同的輸入應該每次產生相同的唯一輸出,碰撞的可能性非常低。 鑒於這些屬性無法在編譯時計算哈希值? 我對哈希很不了解,我通常使用unordered_map,但我想嘗試新的東西以便學習。
std::hash::operator()
不是constexpr
,所以你不能只使用它。 相反,你必須編寫自己的constexpr
哈希函數。 例如,以下是FNV-1a哈希算法 (未經測試):
template <typename Str>
constexpr size_t hashString(const Str& toHash)
{
// For this example, I'm requiring size_t to be 64-bit, but you could
// easily change the offset and prime used to the appropriate ones
// based on sizeof(size_t).
static_assert(sizeof(size_t) == 8);
// FNV-1a 64 bit algorithm
size_t result = 0xcbf29ce484222325; // FNV offset basis
for (char c : toHash) {
result ^= c;
result *= 1099511628211; // FNV prime
}
return result;
}
然后你可以使用它:
int selectMenuOptionString(const std::string& str)
{
switch (hashString(str))
{
case hashString(std::string_view("Selection one")): return 42;
default: return 0;
}
}
請注意,如果您編寫了hashString("Selection one")
,它實際上也會對null終止符進行哈希處理,因此您可能希望有一個重載來捕獲字符串文字,例如:
template <size_t N>
constexpr size_t hashString(char const (&toHash)[N])
{
return hashString(std::string_view(toHash));
}
你需要實現自己的哈希函數,因為沒有合適的std :: hash實例化的constexpr。 這是一個便宜又臟的......
編輯:為了不被賈斯汀的回答羞辱太多,我添加了一個32位分支。
constexpr size_t hash(const char *str) {
static_assert(sizeof(size_t) == 8 || sizeof(size_t) == 4);
size_t h = 0;
if constexpr(sizeof(size_t) == 8) {
h = 1125899906842597L; // prime
} else {
h = 4294967291L;
}
int i = 0;
while (str[i] != 0) {
h = 31 * h + str[i++];
}
return h;
}
您無法在編譯時獲取運行時值的哈希值,不可以。
即使你傳遞了std::hash
一個常量表達式,它也沒有定義為能夠在編譯時進行散列工作。
據我所知(這不遠),你必須想出一些怪異的模板metahackery(或更糟糕的是,宏!)來做到這一點。 就個人而言,如果您的文本輸入在構建時已知,我只是在代碼之外預生成哈希,可能是在一些Python驅動的預構建步驟中。
我只想添加它,因為我覺得它很酷。 我在這里提出了一個問題: constexpr strlen
#include <iostream>
#include <string>
int constexpr strlength(const char* str)
{
return *str ? 1 + strlength(str + 1) : 0;
}
size_t constexpr Hash(const char *first)
{ // FNV-1a hash function
const size_t FNVoffsetBasis = 14695981039346656037ULL;
const size_t FNVprime = 1099511628211ULL;
const size_t count = strlength(first);
size_t val = FNVoffsetBasis;
for (size_t next = 0; next < count; ++next)
{
val ^= (size_t)first[next];
val *= FNVprime;
}
return val;
}
inline void selectMenuOptionString(const std::string& str)
{
switch (Hash(str.c_str()))
{
case Hash("Selection one"): /*Do something*/ break;
case Hash("Selection two"): /*Do something*/ break;
}
}
int main()
{
static_assert(strlength("Hello") == 5, "String length not equal");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.