[英]Compile time hash with constexpr
我在用于在编译时创建SDBM哈希的书中找到了此示例/类。 不幸的是,它无法编译(无论是c ++ 11还是c ++ 14)。 我收到error: call to non-constexpr function
。 我做了一些尝试,但似乎无法完成这项工作。 所以这是我的问题:
完整(不起作用)的示例供您测试:
#include <iostream>
template <int stringLength>
struct SDBMCalculator
{
static inline int Calculate(const char* const stringToHash, int& value)
{
int character = SDBMCalculator<stringLength - 1>::Calculate(stringToHash, value);
value = character + (value << 6) + (value << 16) - value;
std::cout << static_cast<char>(character) << std::endl << value << std::endl << std::endl;
return stringToHash[stringLength - 1];
}
static inline int CalculateValue(const char* const stringToHash)
{
int value = 0;
int character = SDBMCalculator<stringLength>::Calculate(stringToHash, value);
value = character + (value << 6) + (value << 16) - value;
std::cout << static_cast<char>(character) << std::endl << value << std::endl << std::endl;
return value;
}
};
template <>
struct SDBMCalculator<1>
{
static inline int Calculate(const char* const stringToHash, int& value)
{
return stringToHash[0];
}
};
int main()
{
constexpr int eventID = SDBMCalculator<5>::CalculateValue("Hello");
std::cout << eventID << std::endl;
}
非常感谢您的时间和精力!
阅读错误消息:在评估constexpr值时正在调用非constexpr函数。 您是否尝试解决该问题?
当您将所有相关函数用作constexpr
您还会遇到一些其他错误,请注意。 一些说明:
-std=c++14
编译。 C ++ 11对此还不够好。 SDBMCalculator
函数中删除std::cout
上的所有操作-编译时不允许这些操作 在所有相关计算中将int
更改为unsigned int
。 当int
类型的左移溢出时,您将得到未定义的行为。 无符号类型的左移取模取其最大值+1。
error: shift expression '(4723229 << 16)' overflows constexpr int eventID = SDBMCalculator<5>::CalculateValue("Hello")
通过以上所有修复,您的代码将可以使用。 我得到结果:
2873473298
因此,如http://en.cppreference.com
:
constexpr变量必须满足以下要求:
初始化的完整表达式(包括所有隐式转换,构造函数调用等)必须为常量表达式
在assign表达式内:
constexpr int eventID = SDBMCalculator<5>::CalculateValue("Hello");
我们使用未用constexpr标记的CalculateValue
。
然后我们有两个选择:
只需将constexpr
更改为const
或者尝试使CalculateValue
成为constexpr
函数
由于第一个确实很无聊,所以我们将重点放在第二个上,以更好地了解常量表达式的工作原理!
因此,我们首先将CalculateValue
标记为constexpr
static constexpr inline int CalculateValue(const char* const stringToHash)
现在, CalculateValue
必须仅调用constexpr
函数。 因此我们也必须使Calculate
constexpr
。
static constexpr inline int Calculate(const char* const stringToHash, int& value)
这会触发很多编译器错误。
令人惊讶的是,我们可以注意到,将流放入constexpr中并不是一件好事,因为对流的操作未用constexpr标记。 ( operator<<
就像普通函数一样,它不是constexpr)。
因此,我们从那里删除std::cout
!
好吧,差不多了。 我们还必须Calculate
在SDBMCalculator<1>
一个constexpr
太多,因为它可以通过两种计算函数被调用。
最终代码如下所示:
#include <iostream>
template <int stringLength>
struct SDBMCalculator
{
static constexpr inline int Calculate(const char* const stringToHash, int& value)
{
int character = SDBMCalculator<stringLength - 1>::Calculate(stringToHash, value);
value = character + (value << 6) + (value << 16) - value;
return stringToHash[stringLength - 1];
}
static constexpr inline int CalculateValue(const char* const stringToHash)
{
int value = 0;
int character = SDBMCalculator<stringLength>::Calculate(stringToHash, value);
value = character + (value << 6) + (value << 16) - value;
return value;
}
};
template <>
struct SDBMCalculator<1>
{
static constexpr inline int Calculate(const char* const stringToHash, int& value)
{
return stringToHash[0];
}
};
int main()
{
constexpr int eventID = SDBMCalculator<5>::CalculateValue("Hello");
std::cout << eventID << std::endl;
}
当然, 它不会编译! 我们得到:
错误:移位表达式'(4723229 << 16)'溢出[-fpermissive]
值=字符+(值<< 6)+(值<< 16)-值;
这是因为编译器不希望常量表达式中有溢出。
在编译代码时,我们可以不安全地忽略此错误,添加-fpermissive
标志。
g++ example.cpp -o example.exe -fpermissive
现在,它可以编译并正常运行了! 常量表达式修饰符使编译器在编译时计算哈希值。
很好,因为我们不会为此浪费运行时资源,但是如果您使用大量此类模板和constexprs,并使编译器计算出所有内容,那将是致命的缓慢编译!
希望您现在更好地了解constexpr
行为:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.