我在一本书中找到了这个示例/类,用于在编译时创建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;
}
非常感谢您的时间和精力!
答案 0 :(得分:1)
阅读错误消息:在评估constexpr值时,您正在调用非constexpr函数。你试过修理它吗?
当您将所有相关功能设为constexpr
时,您将收到一些需要引起注意的其他错误。一些评论:
-std=c++14
进行编译。 C ++ 11对此不够好。std::cout
函数中移除SDBMCalculator
上的所有操作 - 在编译时不允许这些操作在所有相关计算中将int
更改为unsigned int
。当左移位溢出int
类型时,您会得到一个未定义的行为。无符号类型的左移是以其最大值+ 1为模计算的。
error: shift expression ‘(4723229 << 16)’ overflows
constexpr int eventID = SDBMCalculator<5>::CalculateValue("Hello")
通过以上所有修复,您的代码将起作用。我得到了结果:
2873473298
答案 1 :(得分:1)
正如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标记。
(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;
}
当然它没有编译! 我们得到:
错误:shift表达式'(4723229&lt;&lt; 16)'溢出[-fpermissive]
value = character +(value&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt
这是因为编译器不希望在常量表达式中出现溢出。
编译代码时,我们可以不安全地忽略添加-fpermissive
标志的错误。
g++ example.cpp -o example.exe -fpermissive
现在它编译并且工作得非常好! 常量表达式修饰符使编译器在计算时计算哈希值。
这很好,因为我们不会浪费运行时资源,但是如果你使用大量的这样的模板和constexprs并使编译器计算所有将致命的慢速编译!
我希望您现在更好地理解constexpr
行为:)