【问题标题】:Convert enum class to lvalue reference to its underlying type in C++将枚举类转换为对其在 C++ 中的基础类型的左值引用
【发布时间】: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&lt;std::underlying_type&lt;State&gt;::type&gt;() 时,我仍然收到一条错误消息:

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


【解决方案1】:

问题不在于enum,而在于static_cast 发生了什么。 getBytes 无法将值插入到 static_cast 值中。

但是,您可以创建两个帮助函数来为您执行此操作

template <typename T>
constexpr auto to_integral(T e){
    return static_cast<std::underlying_type_t<T>>(e);
}

State wrapped_getBytes(State in){
    auto i = to_integral(in);
    getBytes(i);
    return State(i);
}

【讨论】:

  • 使用enable_if 或类似的技巧,可以概括代码,使其适用于所有enum 或具有uint8_t 基础类型的那些。如果getBytes 已经为许多类型重载,那么有一个重载的getBytes 可以与枚举一起使用..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-13
  • 2010-10-25
  • 1970-01-01
  • 1970-01-01
  • 2022-12-22
  • 1970-01-01
相关资源
最近更新 更多