【问题标题】:How should we use an enum class for indexing (or should we better avoid this)?我们应该如何使用枚举类进行索引(或者我们应该更好地避免这种情况)?
【发布时间】:2020-01-07 20:17:30
【问题描述】:

假设我们有一个enum 类型foo,我们想用它来索引一个静态大小的数组arr

如果我们想为此使用enum class,我们可以这样尝试:

enum class foo
{
    a,
    b,
    c,
    count
};

std::array<T, static_cast<int>(foo::count)> arr;

但是,count 字段是一个 hack。能不能更优雅的获取foo的字段数?

无论如何,真正糟糕的是我们还需要使用static_cast 访问数组:arr[static_cast&lt;int&gt;(foo::a)]

当然我们可以编写一个自定义的“at”函数(参见https://www.fluentcpp.com/2019/01/15/indexing-data-structures-with-c-scoped-enums/)或提供一个“enum_array”类(参见https://stackoverflow.com/a/55259936/547231),但是这两种解决方案都有些复杂,我们最好放弃并使用一个简单的std::array&lt;T, int&gt; 改为 ...

但是,阅读arr[foo::a] 比阅读arr[0] 更直观,我们总是需要记住后者中索引0 的含义。

我们可以做得更好吗?

【问题讨论】:

  • 真的很糟糕吗?如果您想使用枚举作为索引,为什么不使用普通的旧 enumenum class 主要效果是你需要一个演员,如果你不想要你就不必
  • 使用以枚举为键类型的map/unoredered_map?
  • @NathanOliver 当然,但这不会以查找每个数组访问而告终吗?好像不值这个价。
  • @0xbad 查找将是带有 unordered_map 的 on average O(1)。尤其是如果您的枚举只有 3 个项目,就像示例一样,即使是 O(n) 解决方案也可能不会产生合理的差异。也许您可以告诉我们更多关于您正在尝试做的事情,这使得该操作的运行时如此重要?
  • @scohe001 为什么我要增加开销(即使它具有恒定的复杂性)只是为了比普通的enum 获得这么一点好处?

标签: c++ indexing enums c++17 enum-class


【解决方案1】:

不,不是。

有许多提案可以实现枚举值的静态反射。还没有 C++ 语言。

我的意思是你可以这样做:

namespace foo {
  enum value {
    a,b,c,count
  };
}

那么到 int 的转换是隐式的,你不会污染包含的命名空间。

solution here 的开销非常接近于 0,并允许您使用枚举(并且仅枚举)作为 [] 的键。

所以你得到:

enum_array<foo, T> arr;

arr 的行为就像你想要的那样。

【讨论】:

  • 你确定它只接受枚举作为键吗? using base::operator[] 应该公开此运算符的 size_t 版本。 (并且由于它是struct,因此继承是公开的,因此这些运算符应该已经公开)
  • @n314159 啊,在原帖里注释掉了。随着 using 的消失,标准查找将找不到 base[] 运算符。提到如果你想让[size_t] 工作,你可以评论它。
  • 我认为添加一个关于从没有虚拟析构函数的类中公开继承的危险的警告也是合适的。
  • @n314159 在 999/1000 的情况下,有人在堆上分配原始 std::array(或 enum_array)是在犯错误已经。所以我认为这里不值得多说。更重要的是,虽然标准未定义通过基础删除,但当存在“空”派生扩展时,每个编译器生成的 UB 实际上都会做正确的事情。在两者之间,在实际生产中产生实际问题这种特定情况需要一个非常人为的情况。所以我会过去的。
【解决方案2】:

作为部分解决方案,您可以定义

constexpr std::underlying_type_t<foo> operator*(foo f) {
    return static_cast<std::underlying_type_t<foo>>(f);
}

然后写

int bar(std::array<int, *foo::count>& arr) {
    return arr[*foo::b];
}

Demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-11
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 2022-08-05
    • 1970-01-01
    • 1970-01-01
    • 2015-05-24
    相关资源
    最近更新 更多