在编译时而不是运行时创建一个由两个字节组成的值

Creating a value made out of two bytes at compile-time instead of runtime

我有一个可以用作 uint8_t 的枚举器,我想使用这个枚举器的两个值的组合来创建一个 uint16_t 类型的数字,其中 leftmostrightmost 字节由这 2 个枚举值确定。

然后我需要使用这个结果值作为 unordered_map<uint16_t, something> 的关键元素类型,我在其中存储了几个 something 值。

所以我想出了这段代码,它在 运行 时将两个枚举值解析为一个键。 这些评论只是表明真正的问题涉及的元素比下面示例中显示的要多。

enum Value : uint8_t {
    V1, V2, V3, V4 // , ... , VN
};

static inline uint16_t compose(Value a, Value b) {
    return ((uint16_t) a << 8) | b;
}

static const unordered_map<uint16_t, something> elements = {
    { compose(Value::V3, Value::V1), something1 },
    { compose(Value::V4, Value::V4), something2 },
    { compose(Value::V1, Value::V2), something3 },
    // { ... }, { compose(Value::VA, Value::VB), somethingN }
};

如果我没记错的话,compose 会在程序启动时调用几次,并尝试在 运行ning main 之前初始化变量和常量。

现在是大问题:

Is there a better way to do this in order to compose the number at compile-time instead of runtime?

我可以对数字进行硬编码而不是 运行 组合,但那将是一个非常丑陋且可能不安全的解决方案。

想象一下,如果我不得不调换两个或更多枚举数 "values" 的位置;这将需要对硬编码数字进行完整修改,所以这根本不是一个选项。

维护组成 uint16_t 的两个枚举值的名称也很好,所以当我需要编辑 something 对应于 V1V4 我很容易找到它。

不幸的是,我不认为预处理器可以做这样的事情,我怀疑编译器是否能够优化 compose,即使我使用了 inline 关键字。

请帮助我。

您可以将 compose 标记为 constexpr 函数。这样,编译器就可以将函数的结果用作编译时常量:

inline constexpr uint16_t compose(Value a, Value b) { ... }

在 c++20 中,您可以将 compose 设为 consteval 函数。然后保证在编译时被评估:

consteval std::uint16_t compose(Value a, Value b) {
    return ((std::uint16_t) a << 8) | b;
}

这里是 demo

请注意,如果需要,您将无法在 运行 时调用此函数。