我为我正在从事的项目编写了一个超级愚蠢的序列化库。我刚刚被浮点无穷大所困扰,我用下面的示例程序来说明这一点。我希望程序能够打印inf -> int,但它却打印了inf -> 0。如何使用std::ostream和std::istream接口来修复它,以给出浮点无穷大(和 NaN)的正确答案?
#include <limits>
#include <sstream>
#include <iostream>
void serialize(std::ostream& dst, float src) {
dst << src;
}
void deserialize(float& dst, std::istream& src) {
src >> dst;
}
int main() {
const float original = std::numeric_limits<float>::infinity();
std::stringstream buffer;
serialize(buffer, original);
float parsed;
deserialize(parsed, buffer);
std::cout << original << " -> " << parsed << '\n';
}
Run Code Online (Sandbox Code Playgroud) 我想知道以下是否应该或不应该在 C++17 中编译
enum class E
{
A, B
};
constexpr E x = static_cast<E>(2);
Run Code Online (Sandbox Code Playgroud)
这在 Ubuntu 20.04 上使用 GCC 9.3.0 和 Clang 10.0.0 编译。
我的问题是
我认为不应该。有很多关于未定义行为 (UB) 和枚举的帖子,但我找不到任何在常量表达式上下文中提出的帖子。此外,大多数帖子使用底层类型,我认为范围枚举没有任何固定的底层类型。因为我没有获得ISO标准的副本,我将把最新的C ++发现有17草案cppreference.com这里在下面的推理。
首先,我们找到将带有 UB 的表达式从常量表达式中丢弃的段落
[expr.const]/2:表达式 e 是核心常量表达式,除非 e 的计算遵循抽象机的规则,将计算以下表达式之一:
带小节
[expr.const]/2.6 : 具有未定义行为的操作,如本国际标准的 [intro] 至 [cpp] 条款 [?注:包括,例如,有符号整数溢出(条款 [expr]),某些指针算术([expr.add]),除以零,或某些移位操作?—?尾注?];
这告诉我们常量表达式可能不包含 UB。
然后,我们找到关于从 int 到 enum 的静态转换的部分
[expr.static.cast]/10 : 整数或枚举类型的值可以显式转换为完整的枚举类型。如果原始值在枚举值 ( [dcl.enum] )的范围内,则该值不变。否则,行为是未定义的。浮点类型的值也可以显式转换为枚举类型。结果值与将原始值转换为枚举的基础类型 ([conv.fpint]) 以及随后的枚举类型相同。
这告诉我们,如果操作数在目标枚举的范围内,则静态转换的结果是明确定义的。该部分参考[decl.enum]/8关于枚举值的范围(太长无法在此处发布,我也无法正确设置格式)。无论如何,它表示非固定基础类型枚举的有效值范围由可以适合最小和最大枚举(以两个补码格式)之间的所有值的最小位集定义。
最后,在示例代码中应用这三个部分,我们可以说可以同时包含 A = 0 和 B = 1 的最小位域的大小为 …