在 switch 语句中使用常量数组的元素作为 case
我正在尝试将一组按键映射到一组命令。 因为我处理来自多个位置的命令,所以我想在键和命令之间设置一个抽象层,这样如果我更改底层键映射,就不必更改太多代码。 我当前的尝试如下所示:
// input.h
enum LOGICAL_KEYS {
DO_SOMETHING_KEY,
DO_SOMETHING_ELSE_KEY,
...
countof_LOGICAL_KEYS
};
static const SDLKey LogicalMappings[countof_LOGICAL_KEYS] = {
SDLK_RETURN, // Do Something
SDLK_ESCAPE, // Do Something Else
...
};
// some_other_file.cpp
...
switch( event.key.keysym.key ) {
case LogicalMappings[ DO_SOMETHING_KEY ]:
doSomething();
break;
case LogicalMappings[ DO_SOMETHING_ELSE_KEY ]:
doSomethingElse();
break;
...
}
当我尝试编译此文件(gcc 4.3.2)时,我收到错误消息:
错误:“LogicalMappings”不能出现在常量表达式中
我不明白为什么编译器会出现这个问题。 我理解为什么不允许在 case 语句中使用变量,但我的印象是您可以使用常量,因为它们可以在编译时进行评估。 常量数组不能与 switch 语句一起使用吗? 如果是这样,我想我可以用类似的东西替换数组:
static const SDLKey LOGICAL_MAPPING_DO_SOMETHING = SDLK_RETURN;
static const SDLKey LOGICAL_MAPPING_DO_SOMETHING_ELSE = SDLK_ESCAPE;
...
但这似乎不太优雅。 有谁知道为什么这里不能使用常量数组?
编辑:我已经看到 C++ 标准的一部分声称,“整型常量表达式只能涉及文字 (2.13)、枚举器、const 变量或用常量表达式初始化的整型或枚举类型的静态数据成员 (8.5) ……”。 我仍然不明白为什么常量数组不能算作“用常量表达式初始化的枚举类型”。 我的问题的答案可能只是“因为事情就是这样”,我必须解决这个问题。 但如果是这样的话,那就有点令人失望了,因为编译器确实可以在编译时确定这些值。
I'm attempting to map a set of key presses to a set of commands. Because I process the commands from several places, I'd like to set up a layer of abstraction between the keys and the commands so that if I change the underlying key mappings, I don't have to change very much code. My current attempt looks like this:
// input.h
enum LOGICAL_KEYS {
DO_SOMETHING_KEY,
DO_SOMETHING_ELSE_KEY,
...
countof_LOGICAL_KEYS
};
static const SDLKey LogicalMappings[countof_LOGICAL_KEYS] = {
SDLK_RETURN, // Do Something
SDLK_ESCAPE, // Do Something Else
...
};
// some_other_file.cpp
...
switch( event.key.keysym.key ) {
case LogicalMappings[ DO_SOMETHING_KEY ]:
doSomething();
break;
case LogicalMappings[ DO_SOMETHING_ELSE_KEY ]:
doSomethingElse();
break;
...
}
When I try to compile this (gcc 4.3.2) I get the error message:
error: 'LogicalMappings' cannot appear in a constant-expression
I don't see why the compiler has a problem with this. I understand why you're not allowed to have variables in a case statement, but I was under the impression that you could use constants, as they could be evaluated at compile-time. Do constant arrays not work with switch statements? If so, I suppose I could just replace the array with something like:
static const SDLKey LOGICAL_MAPPING_DO_SOMETHING = SDLK_RETURN;
static const SDLKey LOGICAL_MAPPING_DO_SOMETHING_ELSE = SDLK_ESCAPE;
...
But that seems much less elegant. Does anybody know why you can't use a constant array here?
EDIT: I've seen the bit of the C++ standard that claims that, "An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5)...". I still don't see why a constant array doesn't count as an "enumeration type initialized with a constant expression." It could just be that the answer to my question is "because that's the way that it is," and I'll have to work around it. But if that's the case, it's sort of disappointing, because the compiler really could determine those values at compile-time.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
参考 C++ 标准的部分:6.4.2 要求 case 表达式求值为整数或枚举常量。 5.19 定义了它是什么:
因此,如果您的问题是“为什么编译器拒绝这个”,一个答案是“因为标准是这么说的”。
Referring to sections of the C++ standard: 6.4.2 requires that case expressions evaluate to an integral or enumeration constant. 5.19 defines what that is:
So if your question was "why does the compiler reject this", one answer is "because the standard says so".
无论如何,数组引用都不够“恒定”。
您只需稍微不同地进行映射即可。 您希望在按下逻辑键时发生相同的操作,因此请在
switch
语句的case
子句中使用逻辑键代码。 然后将实际的键代码映射到逻辑代码,可能在switch
本身中,或者可能事先。 您仍然可以使用 LogicalMappings 数组或类似的构造。 而且,作为 G11N(全球化)的辅助手段,您甚至可以使映射数组变得非常量,以便不同的人可以重新映射键以满足他们的需要。Array references aren't "constant enough", regardless.
You just need to do the mapping slightly differently. You want the same action to occur when the logical key is pressed, so use the logical key codes in the
case
clauses of theswitch
statement. Then map the actual key code to the logical code, possibly in theswitch
itself, or possibly before-hand. You can still use the LogicalMappings array, or a similar construct. And, as an aid to G11N (globalization), you can even make the mapping array non-constant so that different people can remap the keys to suit their needs.我会在这里冒险,因为没有其他人回复这个问题,而且我最近主要在做 Java,而不是 C++,但据我所知,数组查找不被视为常量整数,即使查找可以在编译时确定。 这甚至可能是语法中的问题。
I'll go on a limb here since nobody else replied to this and I've been mostly doing Java recently, not C++, but as far as I seem to recall an array lookup is not considered a constant integer even if the result of the lookup can be determined at compile time. This may even be an issue in the syntax.
是否为“LogicalMappings”定义了比较运算符? 如果不是,那就是错误。
Is there a comparison operator defined for the "LogicalMappings"? If not then that is the error.
boost中有一个名为 signal 的库,它将帮助您创建事件映射抽象。如果您有时间,这应该是更好的方法
There is a library called signal in boost that will help you create a event mapping abstraction.If you have time this should be better approach
您还可以使用函数指针或函子数组(我想是函子地址),以避免完全使用 switch 语句 & 只需从数组索引开始 -> 直接函数指针/函子。
例如(警告,后面是未经测试的代码)
you could also use an array of function pointers or functors (I suppose functor addresses), to avoid the switch statement altogether & just go from array index -> function pointer / functors directly.
for example (warning, untested code follows)
一位正在工作的编译器专家向我解释了这一点。 问题是数组本身是常量,但它的索引不一定是常量。 因此,表达式 LogicalMappings[some_variable] 无法在编译时求值,因此数组最终会存储在内存中,而不是被编译出来。 编译器仍然没有理由不能使用 const 或文字索引静态评估数组引用,所以我想做的事情理论上应该是可能的,但它比我想象的要棘手一些,所以我可以理解为什么 gcc 不这样做不要这样做。
A compiler guru at work explained this to me. The problem is that the array itself is constant, but indices to it aren't necessarily const. Thus, the expression LogicalMappings[some_variable] couldn't be evaluated at compile-time, so the array winds up being stored in memory anyway rather than getting compiled out. There's still no reason why the compiler couldn't statically evaluate array references with a const or literal index, so what I want to do should theoretically be possible, but it's a bit trickier than I'd thought, so I can understand why gcc doesn't do it.