In Qt o C ++, c'è un buon mezzo per creare uno switch con casi generati dinamicamente, o dovrei semplicemente usare un ciclo for (o qualcos'altro)?

0

Presumi questa situazione:

  • Numero massimo di 256 posti chiave.
  • Gli slot chiave sono definiti da struct e deve esistere una variabile per ciascuno (256).
  • L'utente definisce quali slot di chiavi sono attivi all'avvio (nel mio esempio, li ho appena codificati). Tuttavia rimarranno constant durante l'esecuzione.
  • Il programma riceve input, lo invia allo slot ed esegue un'azione definita dall'utente.

Entrambi gli esempi di codice presuppongono questa struttura:

struct Key;
QList<Key*> keyList;
struct Key {
    const uint_fast8_t keyNumber; // Unsigned 8 bit integer
    const QString      action;

    /* Constructor - Will add self to keyList if cmd is specified */
    Key(const uint_fast8_t keyNum, const QString cmd="")
        : keyNumber(keyNum),
          action(cmd)
    {
        if (!cmd.isEmpty) { keyList.append(this); }
    }
};

int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        uint_fast8_t inputKey;

        /* All variables have to exist. */
        Key _001(1);
        Key _002(2);
        Key _003(3,  "boat programming"); // Automatically added to keyList
        Key _004(4);
        ...
        Key _075(75);
        Key _076(76, "foo bar");
        Key _077(77);
        ...
        Key _254(254);
        Key _255(255,"take yee flask");

        /* etc... */

Soluzione 1: un interruttore gigante

switch (inputKey) {
    case _001.number: execute(_001.action); break;
    case _002.number: execute(_002.action); break;
    case _003.number: execute(_003.action); break;
    ... 
    ... 
    ... 
    case _255.number: execute(_255.action); break;
    case _256.number: execute(_256.action); break;
    case default: break;
}

Problema: inefficiente se sono definite solo tre azioni

Soluzione 2: un ciclo for su un elenco generato all'inizio.

for (int i=0; i<keyList.length; i++) {
    if (inputKey == keyList.at(i).keyNumber) {
        execute(keyList.at(i).action);
        break;
    }
}

Problema: progressivamente meno efficiente rispetto all'istruzione switch quando vengono aggiunti altri elementi.

Soluzione 3: è possibile?

switch (inputKey) {
    case _003.number: execute(_003.action); break;
    case _076.number: execute(_076.action); break;
    case _255.number: execute(_255.action); break;
    case default: break;
}

Sono sulla buona strada, o dovrei avvicinarmi a questa situazione in modo diverso?

Ovviamente il mio obiettivo è avere il rendimento ottimale entro discrezione ovvia:

    
posta Akiva 18.07.2017 - 15:42
fonte

1 risposta

5

In C ++ 11 o meglio potresti prendere in considerazione l'utilizzo di una mappa di lambdas , ad es.

 std::map<unsigned, std::function<void(void)> actmap;

Lo riempi in modo dinamico, ad esempio

unsigned num = somenumber();
actmap[num] = [=](void) { /* some code for the lambda */ };

Dal momento che hai solo 256 numeri possibili, potresti usare solo il (probabilmente più veloce) std::array<std::function<void(void),256> actmap;

quindi, dato un po 'di num numero, usa

 actmap[num]();

per eseguire quell'azione.

Se utilizzi GCC come compilatore e accetta estensioni non standard, considera -alternatively- usando computed goto -s (alle etichette che iniziano un blocco).

Potresti utilizzare anche un compila JIT approccio meta-programmazione: dai dati iniziali ti generare (eseguibile) il codice al runtime usando una libreria JIT come libgccjit o LLVM o asmjit ecc. Una variante potrebbe essere quella di generare alcune temporanee file contenente un codice C ++ emesso, compilarlo (eseguendo il fork di un compilatore) in un plug-in e utilizzare dlopen ecc. per caricare il plug-in generato. Vedi anche questo e che .

Per quanto riguarda le prestazioni, prova diversi modi e misura i punti di riferimento (non dimenticare di abilitare le ottimizzazioni nel compilatore) e scegli il migliore. Forse l'overhead della chiamata dinamica (e la chiusura) potrebbe non essere così importante.

    
risposta data 18.07.2017 - 15:59
fonte

Leggi altre domande sui tag