首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >检查C++11枚举类的总顺序(如何实现operator<)

检查C++11枚举类的总顺序(如何实现operator<)
EN

Stack Overflow用户
提问于 2016-08-04 22:46:41
回答 3查看 923关注 0票数 2

通常,在编写简单的状态机时,您有一个总顺序,如:

代码语言:javascript
复制
State {
  initial,
  connecting,
  established,
  ready,
  closed,
  failed
}

您可以很容易地测试给定值的等效性:

代码语言:javascript
复制
if (state == State::established)

但是如果你的状态已经准备好了--这个测试会失败,即使准备好意味着已经建立起来了?另一种选择是添加另一个子句,但是随着列表的延长,或者需求的改变,这可能会变得更长。

代码语言:javascript
复制
if (state == State::established || state == State::ready || ...)

使用C样式枚举,您甚至可以通过转换为整数来确定相对顺序:

代码语言:javascript
复制
if (state > State::established && state <= State::closed)

但是,如果您想要享受类型安全枚举类,除了添加operator<之外,您似乎运气不佳。这个是可能的吗?

EN

回答 3

Stack Overflow用户

发布于 2016-08-04 23:21:20

如您所知,作用域枚举提供类型安全性,因为它们不能隐式转换为整数。

但是,没有什么可以阻止您将枚举转换为整数:

代码语言:javascript
复制
if ((int)state > (int)State::established && (int)state <= (int)State::closed)

您可以使用static_cast的C样式强制转换。

票数 1
EN

Stack Overflow用户

发布于 2021-04-21 13:53:17

我倾向于将我需要的操作符定义为内联函数,并根据需要使用static_cast来获得要比较的值:

代码语言:javascript
复制
enum class MyEnum : unsigned { ALPHA, BETA, DELTA, EPSILON };
inline bool operator<(MyEnum a, MyEnum b)  { return static_cast<unsigned>(a) < static_cast<unsigned>(b); }
inline bool operator>(MyEnum a, MyEnum b)  { return static_cast<unsigned>(a) > static_cast<unsigned>(b); }
inline bool operator<=(MyEnum a, MyEnum b) { return static_cast<unsigned>(a) <= static_cast<unsigned>(b); }
inline bool operator>=(MyEnum a, MyEnum b) { return static_cast<unsigned>(a) >= static_cast<unsigned>(b); }

(注意:在C++20中,这会变得更简单,因为您只需定义一个操作符"<=>“操作符,然后自动生成其他操作符)。

在需要执行更复杂技巧的情况下,可以使用静态std::unordered_map将值(或值对)映射到所需的任何值:

代码语言:javascript
复制
#include <unordered_map>

const std::string& getName(MyEnum e)
{
   static const std::string UNKNOWN = "???";
   static const std::unordered_map<MyEnum, std::string> NAMES = {
      {MyEnum::ALPHA,   "ALPHA"},
      {MyEnum::BETA,    "BETA"},
      {MyEnum::DELTA,   "DELTA"},
      {MyEnum::EPSILON, "EPSILON"},
   };
   const auto it = NAMES.find(e);
   return ((it != NAMES.end()) ? it->second : UNKNOWN);
}
票数 0
EN

Stack Overflow用户

发布于 2016-08-04 22:55:45

人们可能会认为这是一个有缺陷的请求,因为对枚举值进行总体排序是一个历史性的实现方法意外,或者状态机很少是线性的(失败意味着关闭,但失败并不一定意味着连接已经准备好)。

然而,我发现它经常出现,直到您转移到更复杂的东西(或者您的状态机增长)为止。我想出了以下解决方案,它不需要将枚举转换为整数值。

代码语言:javascript
复制
bool has_reached(State current, State condition)
{
    bool reached = false;
    switch (condition)
    {
    case State::initial:     reached |= current == State::initial;
    case State::connecting:  reached |= current == State::connecting;
    case State::established: reached |= current == State::established;
    case State::ready:       reached |= current == State::ready;
    case State::closed:      reached |= current == State::closed;
    case State::failed:      reached |= current == State::failed;
    };
    return reached;
}

用途如下:

代码语言:javascript
复制
if (has_reached(state, State::established)) // State::ready returns true

在现代系统中,它应该是快速的,并且很难出错--只要你不把申报的命令和转换的命令混淆在一起。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38778553

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档