llh*_*llh 4 c++ hash template-meta-programming c++11 c++14
我在一本用于在编译时创建 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;
}
Run Code Online (Sandbox Code Playgroud)
预先非常感谢您的时间和精力!
正如所说http://en.cppreference.com:
constexpr 变量必须满足以下要求:
其初始化的完整表达式,包括所有隐式转换、构造函数调用等,必须是常量表达式
在赋值表达式中:
constexpr int eventID = SDBMCalculator<5>::CalculateValue("Hello");
Run Code Online (Sandbox Code Playgroud)
我们使用CalculateValue的是没有用constexpr标记的。
那么我们有两个选择:
只需更改constexpr为const
或者尝试做CalculateValue一个constexpr函数
由于第一个确实很无聊,让我们关注第二个,以更好地理解常量表达式是如何工作的!
所以我们从标记CalculateValue为开始constexpr
static constexpr inline int CalculateValue(const char* const stringToHash)
Run Code Online (Sandbox Code Playgroud)
现在CalculateValue必须仅调用constexpr函数。所以我们也必须做Calculate一个constexpr。
static constexpr inline int Calculate(const char* const stringToHash, int& value)
Run Code Online (Sandbox Code Playgroud)
这会引发很多编译器错误。
幸运的是,我们可以注意到,将流放入 constexpr 中并不是一件好事,因为流上的操作没有用 constexpr 标记。(operator<<就像一个普通函数,它不是 constexpr )。
所以让我们从那里删除std::cout!
好吧,差不多就到了。我们还必须Calculate在SDBMCalculator<1>a中进行 make 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;
}
Run Code Online (Sandbox Code Playgroud)
当然它无法编译! 我们得到:
错误:移位表达式 '(4723229 << 16)' 溢出 [-fpermissive]
值 = 字符 + (值 << 6) + (值 << 16) - 值;
这是因为编译器不希望常量表达式出现溢出。
-fpermissive我们可以在编译代码时添加标志来不安全地忽略此错误。
g++ example.cpp -o example.exe -fpermissive
Run Code Online (Sandbox Code Playgroud)
现在它可以编译并且工作得很好!常量表达式修饰符使编译器在编译时计算哈希值。
这很好,因为我们不会为此浪费运行时资源,但如果您使用大量此类模板和 constexpr 并让编译器计算所有这些,那么编译速度将非常慢!
我希望你constexpr现在能更好地理解行为:)