将结构体转换为uint8_t类型的constexpr数组

6
我需要创建一个由constexpr结构体中的字节组成的constexpr数组。
#include <array>

template<typename T>
constexpr std::array<uint8_t, sizeof(T)> o2ba(const T o) {
    return {};
}

struct A {
    int a;
};

int main() {
    constexpr A x{ 1 };
    constexpr auto y = o2ba(x); // y == { 0x01, 0x00, 0x00, 0x00 } for little endian
    return 0;
}

我试图从联合体中提取它:

template<typename T>
union U {
    T o;
    std::array<uint8_t, sizeof(T)> d;
};

template<typename T>
constexpr std::array<uint8_t, sizeof(T)> o2ba(const T o) {
    return U<T>{o}.d;
}

但是在访问d而不是初始化的o成员时,它会在gcc和msvc编译器上失败。然而,当初始化非constexpr对象时,它可以正常工作,如下所示。

int main() {
    constexpr A x{ 1 };
    auto y = o2ba(x); // y == { 0x01, 0x00, 0x00, 0x00 } for little endian
    return 0;
}

但这不是我需要的。有没有办法做到这一点?

我认为这是做不到的。你需要使用类似于你尝试过的联合体别名变量,或者将其重新解释为不同类型。这两种方法在constexpr上下文中都是不允许的。 - oisyn
1
不可能实现。应该可以为要序列化的每种类型编写自定义序列化函数。这样的自定义序列化函数可以尝试生成尽可能接近内存表示的数组。这样的函数无法移植,因此对于每个支持的平台,您都需要不同的函数。 - Григорий Шуренков
1个回答

2
你想要的是不可能的。在你的代码中,你尝试在 constexpr 上下文中访问一个未初始化的成员,这是可以的。错误在于你随后尝试访问一个非活动成员,而根据[expr.const#2.8],这是不允许的:

表达式 e 是核心常量表达式,除非按照抽象机器的规则对 e 进行评估将评估以下一项表达式之一:

...

  • 应用于联合体或其子对象的非活动成员的 glvalue 的 lvalue-to-rvalue 转换;
现在的替代方案是通过旧的方式将对象序列化为字节,即通过 reinterpret_cast,即 reinterpret_cast<const uint8_t*>(&a)。同样的,在 constexpr 上下文中不允许使用 reinterpret_cast,参见2.15(同一章节)。我怀疑你不能这样做的原因是因为它是不可移植的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接