c++ - 枚举映射对重构具有鲁棒性

标签 c++ enums c++14

我想将(作用域)枚举的值映射到其他一些值。例如,这里我将 Color 映射到其他枚举 Group:

enum class Color {
  Red, Green, Blue, Cyan, Magenta, Yellow, White, Black, 
  COUNT  // Needed to know the number of items
};
enum class Group {
  Primary, Secondary, Neutral
};

Group GetGroupOfColor(Color color);  // Mapping function I'm going to implement

我想确保如果任何人更改 Color 枚举中的元素数量,此函数将无法编译。

我想出了解决这个问题的唯一方法:

Group GetGroupOfColor(Color color)
{
  static const Group color2group[] = {
    Group::Primary,    // Red
    Group::Primary,    // Green
    Group::Primary,    // Blue
    Group::Secondary,  // Cyan
    Group::Secondary,  // Magenta
    Group::Secondary,  // Yellow
    Group::Neutral,    // White
    Group::Neutral     // Black
  };
  static_assert(ARRAY_SIZE(color2group) == size_t(Color::COUNT), "DEADBEEF!");

  auto index = size_t(color);
  assert(index < size_t(Color::COUNT));
  return color2group[index];
}

其中ARRAY_SIZE可以像下面这样实现:

template <typename T, size_t N>
constexpr size_t ARRAY_SIZE(T(&)[N])
{
  return N;
}

这个实现满足了我的要求,但它有很多缺点:

  • Color 枚举中添加这个丑陋的 COUNT 项(最让我烦恼)
  • 如果有人重新订购 Color 的商品,则会失败,且不会提示
  • 不适用于不连续的枚举,即具有显式赋值的枚举(这并不重要)

我的问题是,有没有办法改进这个实现?也许有一些我什至没有想到的不同方法。也许有它自己的缺点,我会觉得不那么烦人。

另请参阅:

最佳答案

我会使用 switch 语句。

switch (colour) {
    case Colour::Red:   return Group::Primary;
    //...
    case Colour::Black: return Group::Neutral;
}
return Group::Invalid;  // or throw, assert, or whatever.

这应该可以满足您的所有需求:

Adds this ugly COUNT item in Color enum (bothers me most)

不需要,每个枚举器只需一个case

Will fail silently if someone reorders items of Color

每个 case 都是显式命名的,因此每个枚举器的值并不重要(只要它们是唯一的;但如果不是这样,您会收到错误)。

Not applicable for not-continuous enums

同样,命名的 case 语句并不关心实际值。

if anyone changes the number of elements in Color enum, this function will fail to compile

虽然不能保证,但大多数编译器应该能够警告开关中是否存在未处理的枚举器(只要没有 default 分支)。对于 GCC,该选项是 -Wswitch(包含在 -Wall 中),如果您希望它导致失败,还可以加上 -Werror

关于c++ - 枚举映射对重构具有鲁棒性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28602114/

相关文章:

c++ - 类静态函数中变量的非静态成员引用

c++ - 在 RAM 中保留数据,同时允许其他进程在 linux C++ 中访问它

c++ - PI调节比例积分算法的公式

c# - 使用枚举设置元素的可见性?

c++ - qt creator 如何从主窗口获取布局?

c++ - 尝试将记录中的数据读入程序时难以捉摸的错误(C++)

c++ - 在 C++ 中编译类的代码时,控制流的顺序是什么?

ruby-on-rails - Rails 4 枚举验证

java - 具有 "my type"列的数据库表

c++ - 将编译时已知函数参数转换为 std::integral_constant 的有效方法