2010-06-27 14 views
8

stavo avendo uno sguardo alla "Funzione" documentazione di classe in Boost, e siamo imbattuti in questo:C++ strana sintassi avvistato in modello Boost Parametri

boost::function<float (int x, int y)> f; 

devo ammettere questa sintassi è estremamente confusa per me. Come può essere legale C++?

C'è qualche trucco sotto il cofano? Questa sintassi è documentata ovunque?

+0

Si prega di fare solo una domanda per domanda - se avete due domande da porre, invia due domande separate. – bdonlan

+0

Vero, scusa, non lo farò di nuovo – Dinaiz

+0

Puoi modificare la tua domanda per rimuovere una delle domande per dividerlo in un'altra domanda: è difficile rispondere in questo modo perché se qualcuno conosce solo la risposta a una delle tue domande , si sentiranno riluttanti a presentare una risposta. – bdonlan

risposta

9

[Modifica] Questa è una risposta alla domanda originale e inedita dell'autore, che in realtà era composta da due domande.

Devo ammettere che questa sintassi è altamente che mi confonde. Come può essere questo il C++ legale ? :) C'è qualche trucco sotto il cofano? Questa sintassi è documentata ovunque?

Questo è perfettamente legale e in realtà non è troppo complicato.

template <class T> 
class C 
{ 
public: 
    T* function_pointer; 
}; 

void fn(int x) 
{ 
    cout << x << endl; 
} 

int main(int argc, char** argv) 
{ 
    C<void (int x)> c; 
    c.function_pointer = &fn; 
    c.function_pointer(123); // outputs x 
} 

E 'fondamentalmente la stessa cosa che fare:

typedef void Function(int); 
C<Function> c; 

Questo tipo non è solo applicabile C++, è altrettanto applicabile in C (il tipo effettivo C è parametrizzato a). Il modello magico qui sta prendendo qualcosa di simile alla funzione typedef qui e in grado di rilevare i tipi dei valori restituiti e degli argomenti. Spiegando che sarebbe troppo lungo qui e boost :: function utilizza molti dei meta-template di tratti di funzione in boost per recuperare tali informazioni. Se vuoi davvero passare il tempo per imparare questo, dovresti provare a capire l'implementazione del boost a partire da boost :: function_traits in Boost.Type Traits.

Tuttavia, desidero risolvere il problema generale. Penso che tu stia tentando troppo per semplificare un paio di righe di codice perfettamente accettabile. Non c'è niente di sbagliato nel passare gli argomenti per le sottoclassi del comando attraverso i loro costruttori di sottoclassi parametrizzati. Vale veramente la pena tentare di coinvolgere le liste di caratteri e le soluzioni boost :: function come qui, aumentando così i tempi di compilazione e la complessità del codice in modo significativo, solo per quello?

Se si vuole ridurre ulteriormente, basta scrivere una funzione che verrà eseguito ogni sottoclasse di comando e aggiungerlo alla stack di annullamento e così via eseguire:

typedef boost::shared_ptr<Command> CommandPtr; 

void execute(const CommandPtr& cmd) 
{ 
    cmd->execute(); 
    // add command to undo stack or whatever else you want to do 
} 

// The client can simply write something like this: 
execute(CommandPtr(new CmdAdd(some_value)); 

Credo davvero che il trade-off di provare renderlo più complicato non vale la pena. Gli autori di boost volevano scrivere una soluzione estremamente generica per la funzione boost :: che sarebbe stata utilizzata da molte persone su molte piattaforme e compilatori. Tuttavia, non hanno tentato di generalizzare un sistema di comandi in grado di eseguire funzioni con firme diverse attraverso un sistema di annullamento unificato (richiedendo in tal modo che lo stato di questi comandi fosse preservato anche dopo aver inizialmente terminato di chiamarli ed essere in grado di annullare e ri -eseguirli senza specificare nuovamente i dati dello stato originale sulle esecuzioni successive). Per questo, il tuo approccio basato sull'eredità è molto probabilmente il migliore e più diretto.

+2

'typedef float (int, int) Command', mi dispiace dirlo, non è legale C. Il codice C corretto sarebbe' typedef float Command (int, int) '. 'typedef' prende una dichiarazione regolare, e invece di definire l'oggetto nominato (es. funzione o variabile), usa il nome come alias per tipo di tipo dell'oggetto. –

+0

+1 Ottima risposta – fingerprint211b

+0

@Dale Ci scusiamo, tu sei corretto e questo è anche illegale in C++. Si è trattato di un errore affrettato quando si cercava di spiegare a quale C era parametrizzato con C c; È l'equivalente della scrittura: typedef float Command (int, int); C c. L'ho modificato per correggere l'errore. – stinky472