2008-12-15 5 views
6

Ich versuche, eine Reihe von Tastendrücken einer Reihe von Befehlen zuzuordnen. Da ich die Befehle von mehreren Stellen aus verarbeite, möchte ich eine Abstraktionsschicht zwischen den Schlüsseln und den Befehlen einrichten, so dass ich, wenn ich die zugrunde liegenden Schlüsselzuordnungen ändere, nicht sehr viel Code ändern muss. Mein aktueller Versuch sieht wie folgt aus:Verwenden von Elementen eines konstanten Arrays als Fälle in einer switch-Anweisung

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

Wenn ich versuche, diese (gcc 4.3.2) Ich Meldung erhalten, den Fehler zu kompilieren:

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

Ich sehe nicht, warum der Compiler ein Problem hat mit diesem. Ich verstehe, warum Sie nicht Variablen in einer case-Anweisung haben dürfen, aber ich hatte den Eindruck, dass Sie Konstanten verwenden könnten, da sie zur Kompilierzeit ausgewertet werden könnten. Funktionieren konstante Arrays nicht mit Switch-Anweisungen? Wenn ja, nehme ich an, ich könnte das Array nur durch etwas wie ersetzen:

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

Aber das scheint viel weniger elegant. Weiß jemand, warum Sie hier kein konstantes Array verwenden können?

EDIT: Ich habe das Bit des C++ - Standards gesehen, der behauptet, dass "ein Integral-Konstantenausdruck nur Literale (2.13), Enumeratoren, Const-Variablen oder statische Datenelemente von Integral- oder Aufzählungstypen mit Konstanten initialisieren kann Ausdrücke (8.5) ... ". Ich verstehe immer noch nicht, warum ein konstantes Array nicht als "Aufzählungstyp mit einem konstanten Ausdruck initialisiert" zählt. Es könnte einfach sein, dass die Antwort auf meine Frage lautet: "Weil das so ist", und ich muss mich darum kümmern. Aber wenn das der Fall ist, ist es irgendwie enttäuschend, weil der Compiler diese Werte zur Kompilierzeit bestimmen kann.

+0

Ein "Aufzählungstyp initialisiert mit einem konstanten Ausdruck" ist etwas wie "MyEnum a = 12", wobei MyEnum ein Aufzählungstyp ist (d. H. Mit dem Schlüsselwort enum deklariert/definiert). Ein Array-of-enum-Typ ist nicht identisch mit dem enum-Typ, aus dem er besteht. –

Antwort

0

Ist für die "LogicalMappings" ein Vergleichsoperator definiert? Wenn nicht, dann ist das der Fehler.

+0

Ich bin mir nicht sicher, ob ich verstehe, was du meinst ... kannst du es ausarbeiten? –

+0

Was ich fragen wollte, war, ob ein Gleichheitsoperator für die Klasse LogicalMappings überladen ist. Da die 'swicth'-Blöcke den Gleichheitsoperator verwenden, um den' Fall 'zu finden. –

1

Ich werde hier auf ein Bein gehen, da niemand anderes darauf geantwortet hat und ich habe Java vor kurzem gemacht, nicht C++, aber soweit ich mich erinnere, wird eine Array-Suche nicht als eine konstante ganze Zahl betrachtet Das Ergebnis der Suche kann zur Kompilierzeit bestimmt werden. Dies kann sogar ein Problem in der Syntax sein.

2

Array-Referenzen sind nicht "konstant genug", unabhängig.

Sie müssen nur die Zuordnung etwas anders machen. Sie möchten, dass die gleiche Aktion ausgeführt wird, wenn die logische Taste gedrückt wird. Verwenden Sie daher die logischen Tastencodes in den case-Klauseln der switch-Anweisung. Dann ordnen Sie den tatsächlichen Schlüsselcode dem logischen Code zu, möglicherweise in dem switch selbst oder möglicherweise vorher. Sie können weiterhin das LogicalMappings-Array oder ein ähnliches Konstrukt verwenden. Und als Hilfe für G11N (Globalisierung) können Sie sogar das Mapping-Array nicht konstant machen, so dass verschiedene Leute die Schlüssel ihren Bedürfnissen entsprechend neu zuordnen können.

3

In Bezug auf Abschnitte des C++ - Standards: 6.4.2 erfordert, dass Case-Ausdrücke zu einer Integral- oder Enumerationskonstante ausgewertet werden. 5.19 definiert, was das heißt:

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.

Also, wenn Ihre Frage ist, „warum die Compiler lehnen dies“ eine Antwort „weil der Standard sagt so“.

-1

So etwas wie LOGICAL_MAPPING_DO_SOMETHING = SDLK_RETURN ergibt die gleichen Werte, so dass Ihr Mapping zu einer Operation x-> x wird.

Warum nicht Template-Klasse mit statischen const Mitglied oder Enumerationskonstante verwenden, sagen wir, Wert, bieten nessesary Mapping mit Spezialisierungen und dann könnte man

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

Funktioniert nicht ... –

0

Es schreiben ist eine Bibliothek namens signal in Auftrieb, die helfen Sie erstellen ein Ereignis Mapping Abstraktion. Wenn Sie Zeit haben, sollte dies besser sein Ansatz

0

Sie könnten auch ein Array von Funktionszeigern oder Funktoren verwenden (ich vermute Funktor-Adressen), um die Switch-Anweisung insgesamt zu vermeiden & gehen Sie einfach aus Array-Index -> Funktionszeiger/Funktoren direc tally.

zum Beispiel (Warnung, nicht getesteten Code folgt)

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

Ein Compiler-Guru bei der Arbeit erklärt mir dies. Das Problem ist, dass das Array selbst konstant ist, aber Indizes zu ihm sind nicht notwendigerweise konstant. Daher konnte der Ausdruck LogicalMappings [some_variable] zur Kompilierzeit nicht ausgewertet werden, sodass das Array im Speicher gespeichert wird und nicht kompiliert wird. Es gibt immer noch keinen Grund, warum der Compiler die Array-Referenzen nicht statisch mit einem const- oder literal-Index auswerten könnte. Was ich tun möchte, sollte theoretisch möglich sein, aber es ist etwas kniffliger, als ich gedacht habe tu es nicht.

Verwandte Themen