【发布时间】:2020-12-19 12:07:22
【问题描述】:
我在 C++11 中有以下代码(大大简化以省略不必要的代码):
#include <cstdint>
#include <type_traits>
enum class State : std::uint8_t
{
Shutdown,
Loading,
Active,
Idle,
Off
};
int main()
{
State state = State::Shutdown;
getBytes(state);
}
getBytes() 是一个库函数,用于反序列化流中的数据:
void getBytes(std::uint8_t& buf) {
// in real codebase it would read from stream and modify buf
// here for simplicity I just modify the argument passed by reference
buf = 1;
}
我面临的问题是作用域枚举不能隐式转换为uint8_t,所以我得到一个编译器错误。当我添加通常的static_cast<std::underlying_type<State>::type>() 时,我仍然收到一条错误消息:
error: no matching function for call to 'getBytes'
getBytes(static_cast<uint8_t>(state));
^~~~~~~~
note: candidate function not viable: expects an l-value for 1st argument
void getBytes(std::uint8_t& buf) {
^
根据Is it safe to reinterpret_cast an enum class variable to a reference of the underlying type?这里的答案,不建议在这种情况下使用reinterpret_cast。
我找到了一种解决方案,即创建一个底层类型的临时变量,然后将其传递给函数,然后像这样修改枚举值:
int main()
{
State state = State::Shutdown;
using UnderlyingType = std::underlying_type<State>::type;
UnderlyingType temp = static_cast<UnderlyingType>(state);
getBytes(temp);
state = static_cast<State>(temp);
}
但是,由于代码库中有很多地方都存在同样的问题,我不认为这是一个很好的解决方案。所以我的问题是有没有办法调用函数getBytes而不创建这个临时的?
附带说明,由于getBytes 是一个库函数,我无法对其进行修改。
【问题讨论】:
-
我相当肯定将其更改为
enum而不是enum class可以解决此问题。是的,enum class更好,但如果在使用老派enum和复制粘贴相同的 5 行之间进行权衡,我认为仅使用枚举也不是犯罪。 -
您可以将样板代码移动到重载函数模板中(同时使用带有std::is_enum 的 SFINAE 以确保它仅限于
enums):Live Demo on coliru -
仅出于类型安全的考虑,才建议使用枚举类。但是,如果您正在使用遗留库函数等,您应该只使用有效的。您可以构建一个内部使用枚举或 uint8_t 的包装函数(类),然后将其转换为您的枚举类类型。但在每种情况下,尽量少使用重新解释演员表(如果有的话)。
标签: c++ c++11 enums enum-class