C ++ 0x: Speichern eines beliebigen Typs von std :: function in einer std :: map

8

Ich versuche, eine Menge von std :: -Funktion in einer Karte (unter GCC 4.5) zu speichern

Ich möchte 2 Arten von Dingen bekommen:

  • Speichern von Funktionen mit bereits übergebenen Argumenten; dann hast du es einfach um f ()
  • aufzurufen
  • Speichern von Funktionen ohne Argumente; dann musst du anrufen f (...)

Ich denke, ich habe den ersten mit einem Klassenbefehl und einem Manager erreicht:

%Vor%

kann wie folgt verwendet werden:

%Vor%

Nun würde ich gerne in der Lage sein, dies zu tun:

%Vor%

Gibt es einen Weg, zB mit type-radition?

    
codablank 02.10.2011, 01:16
quelle

3 Antworten

8

Sie können den dynamischen Typ verwenden, um den Typ der Funktion in der Liste zur Laufzeit zu bestimmen. Bitte beachten Sie, dass ich shared_ptr hinzugefügt habe, um das Speicherleck im ursprünglichen Beispiel zu entfernen. Vielleicht möchten Sie eine Ausnahme auslösen, wenn die Methode execute mit den falschen Argumenten aufgerufen wird (wenn die dynamische_Ausgabe 0 ergibt).

Verwendung:

%Vor%

Code (mit variadic Vorlagenunterstützung zum Beispiel gcc-4.5):

%Vor%

ohne variadische Template-Unterstützung (Beispiel VS2010):

%Vor%     
David Feurle 02.10.2011 03:00
quelle
3

Was Sie zu tun versuchen, ist ohne eine ernsthafte Laufzeitarbeit und die damit verbundenen Kosten nicht möglich. Die einfachste Lösung wäre natürlich, einfach eine boost :: any zu speichern ( any_function hat es nie in boost geschafft) und mache die notwendigen Umwandlungen (oder füge ein paar Laufzeitdaten hinzu, die dir sagen, welche Cast zu machen ist), obwohl du das um jeden Preis vermeiden solltest und mit festen Argumenten oder ohne Argumente gehen solltest. Ihre Benutzer können dann ihre Funktionen ändern, indem sie bind verwenden, um sie an die von Ihnen gewünschte Signatur anzupassen.

Bearbeiten: In Ihrem aktuellen Schema sehe ich keinen Grund für CommandManager , Command* in der Map zu speichern.

Bearbeiten2: Sie legen auch den Rückgabetyp ab. Dies könnte für Ihren Anwendungsfall in Ordnung sein, macht dies jedoch viel weniger generisch.

Edit3: Ich habe ein funktionierendes Beispiel Ihres Codes mit any ausgearbeitet. Ich habe das Gefühl, dass es einen Fehler gibt, und ich sehe wirklich nicht, was dies erreichen sollte, aber hier geht es:

%Vor%

Für das Beispiel, das eine feste Signatur verwendet. Denken Sie nur daran, was die natürlichste Darstellung einer Funktion ist, die Sie speichern möchten (wenn Sie Ihr Beispiel Command betrachten, nehme ich an, dass es std::function<void(void)> ist). Speichern Sie Funktionen dieses Typs und wann auch immer Ihre Benutzer versuchen, sie zu verwenden Er muss bind unabhängig von der Funktion, die er verwenden möchte, damit diese Signatur übereinstimmt.

    
pmr 02.10.2011 13:34
quelle
2

Ihr Command -Klassenkonstruktor benötigt ein function<void()> . Sie versuchen es mit einem function<void(string,string)> zu füttern. Dies wird nicht zum Typcheck.

Wenn Sie Funktionen benötigen, die variable Argumente akzeptieren (wie printf ), benötigen Sie function<> und execute() , die variable Argumente akzeptieren. Sie müssen wissen, wie Sie damit arbeiten (insbesondere benötigen Sie ein festes erstes Argument). Sie sind dann für die Typensicherheit verantwortlich, ähnlich wie bei printf .

Wenn Sie nur eine variable Anzahl von String-Argumenten benötigen, verwenden Sie Funktionen, die z. Vektoren von Strings.

All dies hat mit std::map überhaupt nichts zu tun. Was immer Sie in einer einfachen alten Variablen speichern können, können Sie auch in std::map speichern.

    
n.m. 02.10.2011 02:38
quelle

Tags und Links