枚举映射对重构具有鲁棒性
Enum mapping robust to refactoring
我想将(作用域(枚举的值映射到其他一些值。例如,在这里我将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
我想确保如果有人更改 enum 中的元素数量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;
}
这个实现做了我想要的,但它有很多缺点:
- 在枚举
- 中添加这个丑陋
COUNT
项目Color
(最困扰我( - 如果有人重新订购
Color
项目,将静默失败 - 不适用于不连续的枚举,即具有显式分配的值(这个并不重要(
我的问题是,有没有办法改进这种实现?也许我什至没有想到一些不同的方法。也许有它自己的缺点,我会觉得不那么烦人。
另请参阅:
- 枚举中的元素数
- 不使用宏进行编译时sizeof_array
我会使用switch
语句。
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
。
如果有人重新订购
Color
项目,将静默失败
每个case
都显式命名,因此每个枚举器的值无关紧要(只要它们是唯一的;但如果不是这种情况,则会收到错误(。
不适用于不连续枚举
同样,命名case
语句不关心实际值。
如果有人更改了
Color enum
中的元素数量,此函数将无法编译
虽然不能保证,但大多数编译器应该能够警告开关中是否存在未经处理的枚举器(只要没有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;
}
我怀疑您想检测对Color
枚举的更改,因为您想确保每种颜色始终可以映射到某个组?如果是这样,您可以使用一些宏来建立映射,这使得如果不定义映射到的内容,就无法添加新的Color
值。像这样:
#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_COLOR
将允许您从单个源定义Color
枚举以及映射函数:
#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;
}
相关文章:
- 多态性和功能结合
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 如何重构类层次结构以避免菱形问题
- Visual studio代码重构似乎不起作用(例如,重命名符号-f2)
- 为什么与常规GCC不同,即使有"学究性错误",MinGW-GCC也能容忍丢失的返回类型
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 松弛原子与无同步情况下的记忆连贯性
- C++Union/Struct位域的实现和可移植性
- C++boost序列化多态性问题
- 如何更改唯一指针向量的可见性
- 获取 SFML 窗口的 HWND 和高可用性?
- 当指向对象的指针作为参数传递给 std::thread 时,内存可见性
- 为什么 std::reduce 需要交换性?
- 如何查找哪个类对象位于数组的特定索引上(多态性)
- 如何在多线程中正确使用unique_ptr进行多态性?
- 枚举映射对重构具有鲁棒性
- pthread_mutex_lock __pthread_mutex_lock_full:断言失败,具有鲁棒性和0x40
- 代码重构尝试使用多态性和std::map
- 鲁棒,快速复杂多边形(带孔)三角测量c/c++库与许可许可
- C++、点和线在2D中的位置对舍入误差和位置具有鲁棒性