Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 枚举映射对重构具有鲁棒性_C++_Enums_C++14 - Fatal编程技术网

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

C++ 枚举映射对重构具有鲁棒性,c++,enums,c++14,C++,Enums,C++14,我想将(作用域)枚举的值映射到其他一些值。例如,这里我将Color映射到其他枚举组: 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
映射到其他枚举

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
enum中的元素数,此函数将无法编译。

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

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];
}
此实现符合我的要求,但它有一系列缺点:

  • Color
    enum中添加此丑陋的
    COUNT
    项(最让我烦恼)
  • 如果有人重新排序
    颜色的项目
  • 不适用于非连续枚举,即具有显式赋值的枚举(此枚举并不重要)
我的问题是,有什么方法可以改进这个实现吗?可能是一些我没有想到的不同方法。也许有它自己的缺点,我会觉得不那么烦人

另见:


我会使用
开关
语句

switch (colour) {
    case Colour::Red:   return Group::Primary;
    //...
    case Colour::Black: return Group::Neutral;
}
return Group::Invalid;  // or throw, assert, or whatever.
这将满足您的所有需求:

Color enum
中添加此丑陋的
COUNT
项(最困扰我)

不需要这样做,每个枚举数只需要一个
大小写

如果有人重新排序
颜色的项目

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

不适用于非连续枚举

同样,named
case
语句不关心实际值

如果任何人更改
颜色枚举中的元素数
,此函数将无法编译


虽然不能保证,但大多数编译器应该能够在开关中有未处理的枚举数时发出警告(只要没有
default
分支)。对于GCC,选项是
-Wswitch
(包含在
-Wall
)以及
-Werror
,如果您想让它引起故障。

我会使用
开关
语句

switch (colour) {
    case Colour::Red:   return Group::Primary;
    //...
    case Colour::Black: return Group::Neutral;
}
return Group::Invalid;  // or throw, assert, or whatever.
这将满足您的所有需求:

Color enum
中添加此丑陋的
COUNT
项(最困扰我)

不需要这样做,每个枚举数只需要一个
大小写

如果有人重新排序
颜色的项目

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

不适用于非连续枚举

同样,named
case
语句不关心实际值

如果任何人更改
颜色枚举中的元素数
,此函数将无法编译


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

稍微不同的方法如何-创建一种丰富的枚举:

class Color {
  public :
    enum class Name { RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW, WHITE, BLACK };
    enum class Group { PRIMARY, SECONDARY, NEUTRAL };

    uint32_t rgb;
    Name name;
    Group group;

    static const Color Red;
    static const Color Green;
    static const Color Blue;
    static const Color Cyan;
    static const Color Magenta;
    static const Color Yellow;
    static const Color White;
    static const Color Black;

  private :
    Color(uint32_t rgb, Name name, Group group) : rgb(rgb), name(name), group(group) { }

  public :
    inline operator const Name() const { return name; }
};

const Color Color::Red     = Color(0xFF0000, Color::Name::RED,     Color::Group::PRIMARY);
const Color Color::Green   = Color(0x00FF00, Color::Name::GREEN,   Color::Group::PRIMARY);
const Color Color::Blue    = Color(0x0000FF, Color::Name::BLUE,    Color::Group::PRIMARY);
const Color Color::Cyan    = Color(0x00FFFF, Color::Name::CYAN,    Color::Group::SECONDARY);
const Color Color::Magenta = Color(0xFF00FF, Color::Name::MAGENTA, Color::Group::SECONDARY);
const Color Color::Yellow  = Color(0xFFFF00, Color::Name::YELLOW,  Color::Group::SECONDARY);
const Color Color::White   = Color(0xFFFFFF, Color::Name::WHITE,   Color::Group::NEUTRAL);
const Color Color::Black   = Color(0x000000, Color::Name::BLACK,   Color::Group::NEUTRAL);
然后可以这样使用:

void fun(const Color& color) {
    switch (color) {
        case Color::Name::RED   : std::cout << "red"; break;
        case Color::Name::GREEN : std::cout << "green"; break;
        case Color::Name::BLUE  : std::cout << "blue"; break;
        // etc.
    }
    std::cout << " ";
    switch (color.group) {
        case Color::Group::PRIMARY   : std::cout << "primary"; break;
        case Color::Group::SECONDARY : std::cout << "secondary"; break;
        case Color::Group::NEUTRAL   : std::cout << "neutral"; break;
    }
    std::cout << " : " << std::hex << color.rgb << std::endl;
}
void乐趣(常量颜色和颜色){
开关(彩色){

case Color::Name::RED:std::cout稍微不同的方法如何-创建一种丰富的枚举:

class Color {
  public :
    enum class Name { RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW, WHITE, BLACK };
    enum class Group { PRIMARY, SECONDARY, NEUTRAL };

    uint32_t rgb;
    Name name;
    Group group;

    static const Color Red;
    static const Color Green;
    static const Color Blue;
    static const Color Cyan;
    static const Color Magenta;
    static const Color Yellow;
    static const Color White;
    static const Color Black;

  private :
    Color(uint32_t rgb, Name name, Group group) : rgb(rgb), name(name), group(group) { }

  public :
    inline operator const Name() const { return name; }
};

const Color Color::Red     = Color(0xFF0000, Color::Name::RED,     Color::Group::PRIMARY);
const Color Color::Green   = Color(0x00FF00, Color::Name::GREEN,   Color::Group::PRIMARY);
const Color Color::Blue    = Color(0x0000FF, Color::Name::BLUE,    Color::Group::PRIMARY);
const Color Color::Cyan    = Color(0x00FFFF, Color::Name::CYAN,    Color::Group::SECONDARY);
const Color Color::Magenta = Color(0xFF00FF, Color::Name::MAGENTA, Color::Group::SECONDARY);
const Color Color::Yellow  = Color(0xFFFF00, Color::Name::YELLOW,  Color::Group::SECONDARY);
const Color Color::White   = Color(0xFFFFFF, Color::Name::WHITE,   Color::Group::NEUTRAL);
const Color Color::Black   = Color(0x000000, Color::Name::BLACK,   Color::Group::NEUTRAL);
然后可以这样使用:

void fun(const Color& color) {
    switch (color) {
        case Color::Name::RED   : std::cout << "red"; break;
        case Color::Name::GREEN : std::cout << "green"; break;
        case Color::Name::BLUE  : std::cout << "blue"; break;
        // etc.
    }
    std::cout << " ";
    switch (color.group) {
        case Color::Group::PRIMARY   : std::cout << "primary"; break;
        case Color::Group::SECONDARY : std::cout << "secondary"; break;
        case Color::Group::NEUTRAL   : std::cout << "neutral"; break;
    }
    std::cout << " : " << std::hex << color.rgb << std::endl;
}
void乐趣(常量颜色和颜色){
开关(彩色){

case Color::Name::RED:std::cout我怀疑您想检测对
颜色
枚举的更改,因为您想确保每个颜色都可以映射到某个组?如果是这样,您可以使用一些宏来建立映射,这样就不可能添加新的
颜色
值,而不定义它映射到的对象。S像这样的东西:

#define COLORMAP \
  MAP_COLOR(Red, Primary) \
  MAP_COLOR(Green, Primary) \
  MAP_COLOR(Blue, Primary) \
  MAP_COLOR(Cyan, Secondary) \
  MAP_COLOR(Magenta, Secondary) \
  MAP_COLOR(Yellow, Secondary) \
  MAP_COLOR(White, Neutral) \
  MAP_COLOR(Black, Neutral)
适当定义
MAP\u COLOR
将允许您从单个源定义
COLOR
enum以及映射函数:

#define MAP_COLOR(a, b) a,
enum class Color {
  COLORMAP
  Invalid
};
#undef MAP_COLOR

enum class Group {
  Primary, Secondary, Neutral, Invalid
};

#define MAP_COLOR(a, b) case Color::a: return Group::b;
Group GetGroupOfColor(Color color)
{
  switch (color) {
    COLORMAP
    case Color::Invalid: return Group::Invalid;
  }
  return Group::Invalid;
}

我怀疑您想检测对
颜色
枚举的更改,因为您想确保每种颜色都可以映射到某个组?如果是这样,您可以使用一些宏来建立映射,这样就不可能添加新的
颜色
值,而不定义它映射到的对象。例如:

#define COLORMAP \
  MAP_COLOR(Red, Primary) \
  MAP_COLOR(Green, Primary) \
  MAP_COLOR(Blue, Primary) \
  MAP_COLOR(Cyan, Secondary) \
  MAP_COLOR(Magenta, Secondary) \
  MAP_COLOR(Yellow, Secondary) \
  MAP_COLOR(White, Neutral) \
  MAP_COLOR(Black, Neutral)
适当定义
MAP\u COLOR
将允许您从单个源定义
COLOR
enum以及映射函数:

#define MAP_COLOR(a, b) a,
enum class Color {
  COLORMAP
  Invalid
};
#undef MAP_COLOR

enum class Group {
  Primary, Secondary, Neutral, Invalid
};

#define MAP_COLOR(a, b) case Color::a: return Group::b;
Group GetGroupOfColor(Color color)
{
  switch (color) {
    COLORMAP
    case Color::Invalid: return Group::Invalid;
  }
  return Group::Invalid;
}

枚举的全部要点是它们应该是完全独立的类型。您最好的方法是使用switch语句显式地对转换进行编码-但您必须确保两个枚举保持同步,并且在更改其中一个枚举时更改转换代码。枚举的全部要点是它们应该是完全不同的类型。您最好的方法是使用switch语句显式地编写转换代码-但您必须确保两个枚举保持同步,并且在更改其中一个枚举时更改转换代码。我相信这称为“X宏”技术。这很有趣,但非常模糊。它还将
颜色
项的定义与
项相结合。如果我想在其他实体上映射颜色,或者甚至完全摆脱
,该怎么办?@Mikhail:如果你想将颜色映射到其他值,你应该扩展
映射颜色
宏,使其具有三个值(甚至更多)争论。@Mikhail:顺便说一句,谢谢你提到“X宏”,我甚至不知道这项技术有个名字!很高兴你学到了一些新东西:)几天前,当我和我的团队领导讨论同一个问题时,我从我自己那里听到了它。我相信这就是“X宏”技术。这很有趣,但非常模糊。它还将
颜色
项的定义与
相结合