2010-06-27 8 views
8

Ich war in Boost-einen Blick auf die „Funktion“ Klasse Dokumentation mit und über diese gestolpert:C++ seltsame Syntax in Boost-Schablone getupft Parameter

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

Ich muss diese Syntax zulassen, ist für mich sehr verwirrend. Wie kann das legales C++ sein?

Gibt es einen Trick unter der Haube? Ist diese Syntax überall dokumentiert?

+0

Bitte stellen Sie nur eine Frage pro Frage - wenn Sie zwei Fragen haben, geben Sie zwei separate Fragen ein. – bdonlan

+0

Tut mir leid, ich werde es nicht wiederholen – Dinaiz

+0

Sie können Ihre Frage bearbeiten, um eine der Fragen zu entfernen, um sie in eine andere Frage zu trennen - es ist schwierig, so zu antworten, wenn jemand nur die Antwort auf eine Ihrer Fragen kennt , werden sie zögern, eine Antwort zu übermitteln. – bdonlan

Antwort

9

[Bearbeiten] Dies ist eine Antwort auf die ursprüngliche, unbearbeitete Frage des Autors, die eigentlich zwei Fragen war.

Ich muss zugeben, diese Syntax ist sehr verwirrend für mich. Wie kann das sein legale C++? :) Gibt es einen Trick unter der Haube? Ist diese Syntax überall dokumentiert?

Dies ist absolut legal und es ist eigentlich nicht zu kompliziert.

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 
} 

Es ist im Grunde das gleiche wie zu tun:

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

Dieser Typ C nicht nur anwendbar ist ++, es in C genauso anwendbar ist (der tatsächliche Typ C ist parametriert). Die Template-Magie nimmt hier etwas wie den Function typedef und kann die Typen der Rückgabewerte und Argumente erkennen. Dies zu erklären, wäre hier zu langwierig und boost :: function verwendet eine Menge der Meta-Templates der Funktionsmerkmale in Boost, um diese Informationen abzurufen. Wenn Sie wirklich die Zeit dafür nutzen möchten, sollten Sie versuchen, die Boost-Implementierung zu verstehen, die mit boost :: function_traits in Boost.Type Traits beginnt.

Ich möchte jedoch auf Ihr generelles Problem eingehen. Ich denke, Sie versuchen zu sehr, ein paar Zeilen mit absolut akzeptablem Code zu vereinfachen. Es ist nicht falsch, die Argumente für Ihre Befehlsunterklassen über ihre parametrisierten Unterklassenkonstruktoren zu übergeben. Ist es wirklich lohnenswert, hier Typi- listen und boost :: function-like-Lösungen einzubinden, um so die Kompilierzeiten und Codekomplexität signifikant zu erhöhen, nur dafür?

Wenn Sie es weiter reduzieren wollen, schreiben Sie einfach eine Funktion auszuführen, die jeden Befehl Unterklasse ausgeführt werden und es die Rückgängig-Stapel hinzufügen und so weiter:

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)); 

Ich glaube wirklich, den Kompromiss zu versuchen, um es komplizierter zu machen, ist es nicht wert. Die Boost-Autoren wollten eine extrem universelle Lösung für die boost :: function schreiben, die von vielen Leuten auf vielen Plattformen und Compilern verwendet würde. Sie haben jedoch nicht versucht, ein Befehlssystem zu verallgemeinern, das Funktionen mit unterschiedlichen Signaturen über ein einheitliches Undo-System ausführen kann (wodurch der Zustand dieser Befehle auch dann erhalten bleibt, wenn einer sie anfänglich aufruft und rückgängig gemacht werden kann) - Führen Sie sie aus, ohne die ursprünglichen Statusdaten bei nachfolgenden Ausführungen neu festzulegen. Dafür ist Ihr vererbungsbasierter Ansatz wahrscheinlich der beste und geradlinigste Ansatz.

+2

'typedef float (int, int) Command', tut mir leid zu sagen, ist nicht legal C. Der richtige C-Code wäre' typedef float Befehl (int, int) '. 'typedef' verwendet eine reguläre Deklaration, und anstatt das benannte Objekt (dh Funktion oder Variable) zu definieren, verwendet es den Namen als Alias ​​für den Typ des Objekts. –

+0

+1 Große Antwort – fingerprint211b

+0

@Dale Entschuldigung, Sie sind richtig und das ist auch illegal in C++. Das war ein hastiger Fehler beim Versuch, zu erklären, wozu C mit C c parametrisiert wurde; Es entspricht dem Schreiben: typedef float Befehl (int, int); C c. Ich habe es bearbeitet, um den Fehler zu korrigieren. – stinky472