【问题标题】:reinterpret_cast fails constexpr functionreinterpret_cast 使 constexpr 函数失败
【发布时间】:2020-09-25 22:21:51
【问题描述】:

试图创建一个能够重新解释 IEEE 双精度位的 constexpr 类。示例:

constexpr double pi = 3.14159265358979323846;
constexpr fixedpoint a(pi);

但是遇到了 reinterpret_cast 不是常量子表达式的问题。

我在 constexpr fixedpoint& operator=(double rhs) 中使用它:

  uint64_t fraction = *reinterpret_cast<const uint64_t*>(&rhs) & 0x000F'FFFF'FFFF'FFFFull;

但编译器将该语句标记为非常量子表达式。

尝试过类型双关语,但遇到了限制,即在 C++ 中只能激活单个字段。

任何人都有一个解决方案,可以让我重新解释作为有效 constexpr 代码的双精度位吗?

【问题讨论】:

  • reinterpret_cast几乎总是是一个错误。 非常确保它做你想做的,并且在达到它之前它具有明确定义的行为。
  • @JesperJuhl 提取双精度位的“正确”方法是什么?
  • double 布局是well documented:您可以编写一个函数来计算位。如果你发现你需要一些 constexpr 数学支持,有一些选项,例如here。 (如果您只有几个特定的​​值,您可以编写一次性代码来进行非constexpr 转换,然后将输出剪切粘贴到您的源代码中。)
  • @JesperJuhl 这不是真的,OP 显然知道他们在做什么。他们在pi = (-1)^s * 1.xxxxxx * 2^yyyyyy(尾数,或fraction)中提取xxxxxx。但是,请注意 C++ 实际上并不要求 double 是 IEEE 浮点 binary64。这可能就是为什么在 C++20 之前的 constexpr 中不允许这样做的原因,因为编译时计算通常是“抽象的”,而对 double 进行比特处理则相反。

标签: c++ constexpr reinterpret-cast


【解决方案1】:

是的,使用std::bit_cast,它在标题&lt;bit&gt;中:

#include <bit>
#include <cstdint>
constexpr double pi = 3.14159265358979323846;
constexpr auto fraction = std::bit_cast<std::uint64_t>(pi) & 0x000F'FFFF'FFFF'FFFFull;

您需要一个支持 C++20 的编译器。目前还没有,但从 Clang 9 开始,您至少可以使用内置函数,将来用于实现 bit_cast

#if __clang__
constexpr auto fraction = __builtin_bit_cast(std::uint64_t, pi) & 0x000F'FFFF'FFFF'FFFFull;
#endif

Example.

【讨论】:

  • 快速尝试了一下,但显然我还没有兼容 C++20 的编译器....有向后兼容的方法吗? C++14/17ish?
  • @Ravenwater 不,这就是 bit_cast 被添加到标准中的原因 - 它需要编译器魔法来执行 constexpr 中的操作。
  • 感谢您的洞察力,需要弄清楚如何处理该约束(除了不使用 constexpr 定点)......
猜你喜欢
  • 2014-02-24
  • 1970-01-01
  • 2015-06-08
  • 1970-01-01
  • 2020-05-11
  • 2017-06-27
  • 2015-02-09
  • 2019-05-28
相关资源
最近更新 更多