繁体   English   中英

用constexpr编译时间哈希

[英]Compile time hash with constexpr

我在用于在编译时创建SDBM哈希的书中找到了此示例/类。 不幸的是,它无法编译(无论是c ++ 11还是c ++ 14)。 我收到error: call to non-constexpr function 我做了一些尝试,但似乎无法完成这项工作。 所以这是我的问题:

  1. 为什么它不起作用?如何解决? (对不起,我知道这是一个普遍的问题,但至少在特定情况下如此)

完整(不起作用)的示例供您测试:

#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

好吧,差不多了。 我们还必须CalculateSDBMCalculator<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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM