控制枚举值的可见性
考虑一个 C++ 类,该类导出一个枚举,在该枚举上维护一个内部数组,并想要导出一个接受该枚举中的值的命令。
class foo {
public:
enum color {
red,
yellow,
green,
NUM_COLORS
};
private:
something somebody[NUM_COLORS];
public:
void command(color c);
};
有没有一种干净的方法可以仅导出实际颜色,而不导出 NUM_COLORS?当编译器的类型系统确实应该能够为我做这件事时,我不想在每次调用时都检查边缘情况。
明显的黑客行为是:
class foo {
public:
enum color {
red,
yellow,
green
};
private:
/* something like */ const unsigned NUM_COLORS = green+1;
unsigned LEDs_in_stock[NUM_COLORS];
public:
void command(color c);
};
这当然是一个定时炸弹,等待一些可怜的劳累过度的维护程序员添加蓝色 LED 的规定,并忘记更新 NUM_COLORS 行。
让我澄清一下。在这种特殊情况下,我想要的是能够说:
class foo {
public:
enum color {
red,
yellow,
green
};
void command(color c);
private:
something somebody[color];
};
据我所知,C++ 不允许这样做。
Consider a C++ class that exports an enum, maintains an internal array over that enum, and wants to export a command that accepts values from the enum.
class foo {
public:
enum color {
red,
yellow,
green,
NUM_COLORS
};
private:
something somebody[NUM_COLORS];
public:
void command(color c);
};
Is there a clean way to export only the actual colors, but not NUM_COLORS? I do not want to have to check for the edge case on every call when the compiler's type system really ought to be able to do it for me.
The obvious hack is:
class foo {
public:
enum color {
red,
yellow,
green
};
private:
/* something like */ const unsigned NUM_COLORS = green+1;
unsigned LEDs_in_stock[NUM_COLORS];
public:
void command(color c);
};
This of course is a ticking time bomb, waiting for some poor overworked maintenance programmer to add provisions for blue LEDs, and forget to update the NUM_COLORS line.
Let me clarify a bit. What I want, in this particular case, is to be able to say:
class foo {
public:
enum color {
red,
yellow,
green
};
void command(color c);
private:
something somebody[color];
};
It is my understanding that C++ doesn't allow this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
将枚举放入基类中是一种选择吗?
就我个人而言,我不会这样做,因为它看起来过于复杂。我只是禁止调用者传递
NUM_COLORS
。确实,类型系统不会检查这一点。但对于人类程序员来说,检查这无疑是一件容易的事情。为什么他们会通过NUM_COLORS
?Is putting the enumeration into a base class an option?
Personally I wouldn't do this, as it looks like an overly complex work around. I would simply forbid the caller to pass
NUM_COLORS
. True, the type system doesn't check that. But surely this is an easy thing to check for human programmers. Why would they passNUM_COLORS
?我的第一个想法是尝试解决问题,但经过一番思考后,我会将负担转移到命令:
由于枚举是弱类型,因此您需要检查输入无论如何,因为任何人都可以轻松地提供蹩脚的论点:
原始解决方案:
不幸的是,存在大量重复(实际上我最初输入了
green = impl::yellow;
尽管如果您从不这样做也没关系直接引用impl
的值)。否则,总是存在宏技巧:
它使用邪恶的宏和晦涩的预处理器机制来避免代码重复。显然它只适用于连续的枚举元素(它返回元素的数量,而不是最大数量)。
My first thought would be to try and solve the problem as you lay it, but after a bit reflexion, I would shift the burden to
command
:Since enums are so weak types, you need to check the input anyway, as anyone could easily provide crappy arguments:
Original solution:
Unfortunately there is a lot of duplication going on (and I actually originaly typed
green = impl::yellow;
though it does not matter if you never refer toimpl
's values directly).Otherwise, there is always the macro trick:
Which uses an evil macro and obscure preprocessor machinery to avoid code duplicaton. It obviously only works for consecutive enum elements (it returns the number of elements, not the maximum number).
保护未来的维护人员免于犯简单/容易的错误和尝试阻止应该明显错误的事情(例如使用 NUM_COLORS 值)之间有一条微妙的界限。
对于您的情况,我建议在关键函数处断言输入并保留在那里。
我相信您可以使用专门针对 NUM_COLORS 的
static_assert
模板代理类来防止用户将其传递到您的函数中。我输入了一些似乎有效的东西。
There's a fine line between protecting your future maintainers from making simple/easy mistakes, and trying to stop something that should be obviously wrong, such as using the NUM_COLORS value.
In your case I'd suggest asserting the input at key functions and leaving it at that.
I believe you could use a template proxy class that specializes and
static_assert
s on NUM_COLORS to prevent users passing it into your functions.I typed something out that seems to work.
一个解决方案是使用映射:
这样可以保持枚举干净,并且不需要硬编码任何大小。
A solution would be to use a map:
This way you keep you enum clean, and do not need to hard-code any size.