2008-12-15 9 views
6

Estoy intentando asignar un conjunto de teclas presionadas a un conjunto de comandos. Como proceso los comandos desde varios lugares, me gustaría configurar una capa de abstracción entre las teclas y los comandos para que, si cambio las asignaciones de teclas subyacentes, no tenga que cambiar mucho el código. Mi intento actual es el siguiente:Usar elementos de una matriz constante como casos en una instrucción de interruptor

// 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; 
    ... 
} 

Cuando intento compilar este (gcc 4.3.2) me sale el mensaje de error:

error: 'LogicalMappings' cannot appear in a constant-expression

no veo por qué el compilador tiene un problema con este. Entiendo por qué no tiene permitido tener variables en una declaración de caso, pero tenía la impresión de que podría usar constantes, ya que podrían evaluarse en tiempo de compilación. ¿Las matrices constantes no funcionan con las declaraciones de cambio? Si es así, supongo que sólo podía sustituir la matriz con algo como:

static const SDLKey LOGICAL_MAPPING_DO_SOMETHING  = SDLK_RETURN; 
static const SDLKey LOGICAL_MAPPING_DO_SOMETHING_ELSE = SDLK_ESCAPE; 
... 

pero que parece mucho menos elegante. ¿Alguien sabe por qué no puedes usar una matriz constante aquí?

EDIT: He visto el bit de la norma C++ que afirma que "una expresión constante integral puede involucrar solo literales (2.13), enumeradores, variables const o datos estáticos miembros de tipos integrales o de enumeración inicializados con constante expresiones (8.5) ... ". Todavía no veo por qué una matriz constante no cuenta como un "tipo de enumeración inicializado con una expresión constante". Simplemente podría ser que la respuesta a mi pregunta es "porque así es como es" y tendré que evitarlo. Pero si ese es el caso, es un poco decepcionante, porque el compilador realmente podría determinar esos valores en tiempo de compilación.

+0

Un "tipo de enumeración inicializado con una expresión constante" es algo así como "MyEnum a = 12", donde MyEnum es un tipo enumerado (es decir, declarado/definido con la palabra clave enum). Un tipo de matriz de enum no es lo mismo que el tipo de enumeración de la que es una matriz. –

Respuesta

0

¿Hay un operador de comparación definido para los "LogicalMappings"? Si no, ese es el error.

+0

No estoy seguro de entender lo que quieres decir ... ¿puedes dar más detalles? –

+0

Lo que quería preguntar es si hay un operador de igualdad sobrecargado para la clase LogicalMappings. Al ver que los bloques 'swicth' usan el operador de igualdad para encontrar el 'caso'. –

1

Voy a entrar en una extremidad aquí ya que nadie más respondió a esto y he estado haciendo principalmente Java recientemente, no C++, pero por lo que parece recordar una búsqueda de matriz no se considera un entero constante, incluso si el resultado de la búsqueda se puede determinar en tiempo de compilación. Esto incluso puede ser un problema en la sintaxis.

2

Las referencias de matriz no son "lo suficientemente constantes", independientemente.

Solo tiene que hacer la asignación de forma ligeramente diferente. Desea que se produzca la misma acción cuando se pulsa la tecla lógica, por lo tanto, utilice los códigos de clave lógicos en las cláusulas case de la instrucción switch. A continuación, asigne el código de clave real al código lógico, posiblemente en el switch, o posiblemente de antemano. Aún puede usar la matriz LogicalMappings o una construcción similar. Y, como ayuda para G11N (globalización), incluso puede hacer que la matriz de mapeo no sea constante para que diferentes personas puedan reasignar las claves para satisfacer sus necesidades.

3

En referencia a las secciones del estándar C++: 6.4.2 requiere que las expresiones de caso se evalúen a una constante integral o de enumeración. 5.19 define lo que es:

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), non-type template parameters of integral or enumeration types, and sizeof expressions. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used.

Así que si su pregunta fue "¿por qué rechazar el compilador esta", una respuesta es "porque la norma lo dice".

-1

Algo como LOGICAL_MAPPING_DO_SOMETHING = SDLK_RETURN produce los mismos valores, por lo que su asignación se convierte en una operación x-> x.

por qué no utilizar clase de plantilla con el método constante estática o constante de enumeración, por ejemplo, del valor, proporcionar una correlación nessesary con especializaciones, y luego se podría escribir

case LogicalMappings<DO_SOMETHING_KEY>::Value: ... 
+0

No funciona ... –

0

Hay una biblioteca llamada signal en impulso que le ayudará usted crea una abstracción de mapeo de eventos.Si tiene tiempo, esto debería ser mejor enfoque

0

también podría utilizar una matriz de punteros de función o funtores (supongo que las direcciones de functor), para evitar la declaración de interruptor en total & solo vaya desde el índice de matriz -> función puntero/functors direc Tly.

por ejemplo (advertencia, código no probado sigue)

class Event // you probably have this defined already 
{ 
} 

class EventHandler // abstract base class 
{ 
public: 
    virtual void operator()(Event& e) = 0; 
}; 

class EventHandler1 
{ 
    virtual void operator()(Event& e){ 
    // do something here 
    } 
}; 
class EventHandler2 
{ 
    virtual void operator()(Event& e){ 
    // do something here 
    } 
}; 

EventHandler1 ev1; 
EventHandler2 ev2; 
EventHandler *LogicalMappings[countof_LOGICAL_KEYS] = { 
    &ev1, 
    &ev2, 
    // more here... 

}; 

// time to use code: 
Event event; 
if (event.key.keysym.key < countof_LOGICAL_KEYS) 
{ 
    EventHandler *p = LogicalMappings[event.key.keysym.key]; 
    if (p != NULL) 
     (*p)(event); 
} 
0

Un gurú compilador en el trabajo me lo explicó. El problema es que la matriz en sí es constante, pero los índices no son necesariamente const. Por lo tanto, la expresión LogicalMappings [some_variable] no se pudo evaluar en tiempo de compilación, por lo que la matriz termina almacenada en la memoria de todos modos en lugar de compilarse. Todavía no hay ninguna razón por la que el compilador no pueda evaluar estáticamente las referencias de matriz con un índice const o literal, entonces lo que quiero hacer debería ser teóricamente posible, pero es un poco más complicado de lo que pensaba, así que puedo entender por qué no lo hace no lo hagas

Cuestiones relacionadas