0

以下代码旨在创建一种最长 8 个字符的字符串的简单哈希:

#include <type_traits>
#include <cstdint>
#include <iostream>

template<std::size_t N, std::size_t n=N>
constexpr typename std::enable_if<N<=9 && n==0,
uint64_t>::type string_hash(const char (&)[N])
{
    return 0;
}

template<std::size_t N, std::size_t n=N>
constexpr typename std::enable_if<N<=9 && n!=0,
uint64_t>::type string_hash(const char (&array)[N])
{
    return string_hash<N,n-1>(array) | ((array[n-1]&0xffull)<<(8*(n-1)));
}

对于普通字符串文字和 constexpr 以 NULL 结尾的字符串,它确实可以正常工作。但如果我做这样的事情:

constexpr char s2[] = {1,2,3,4,5,6,7,8,9};
std::cout << string_hash(s2) << "\n";

,输出将与字符串相同"\x1\x2\x3\x4\x5\x6\x7\x8"。我尝试static_assert(array[N-1]==0,"Failed");在 的定义中添加 a string_hash,但编译器说这array[N-1]不是常量表达式。然后我尝试声明参数constexpr,但编译器说不能声明参数constexpr

那我该怎么做这个检查?

4

2 回答 2

2

请记住,虽然constexpr函数可以在编译时使用,但它们不是必须的。您不能在运行时参数上添加任何静态断言,因为在编译时参数未知时,将无法评估静态断言。

你可以为非constexpr函数做同样的事情:抛出一些东西。这不会阻止您的函数被无效输入调用,但确实可以防止无提示的错误结果。并且当您的函数在需要常量表达式的上下文中使用时,编译器会正确地检测到它没有返回常量值。

在 C++11 中,函数的主体constexpr需要是一个单独的 return 语句,但您仍然可以将其放入其中:

return array[N-1] ? throw "bad!" : <your current return expression here>;

一定要选择更好的东西来扔。

于 2015-08-01T14:53:28.897 回答
0

编译器抱怨的原因是在函数被实例化array时是未知的。在实例化时评估,而不是在调用时评估(即使它是 constexpr 函数)。string_hash<N,n>static_cast

请注意,将为每对<N,n>值创建一个函数。如果您使用两个相同长度的 constexpr 字符串,将使用完全相同的实例string_hash,但根据参数array[N-1]可能会给出不同的结果。

如果需要,我将继续为您的问题寻找准确的答案。但是,作为“快速修复”,我是否可以建议更改哈希函数,使其始终包含计算中的最后一个字符,无论是否为 0?

更新:在进行了一些挖掘之后,我了解到constexpr_assert您的情况可能需要某种类型的东西,而目前标准中缺少它。希望他们将来会添加它。您可能需要检查:

于 2015-08-01T14:48:23.767 回答