Statische Funktionen von boost.lambda oder boost.phoenix

8

Ich benutze regelmäßig boost.lambda (und phoenix), um Lambda-Funktionen in C ++ zu definieren. Ich mag ihre polymorphe Eigenschaft, die Einfachheit ihrer Darstellung und die Art, wie sie die funktionale Programmierung in C ++ so viel einfacher machen. In einigen Fällen ist es sogar sauberer und besser lesbar (wenn Sie daran gewöhnt sind, sie zu lesen), um kleine Funktionen zu definieren und sie im statischen Bereich zu benennen.

Am besten speichern Sie diese Funktionen, die konventionellen Funktionen ähneln, in boost::function

%Vor%

Aber das Problem ist die Ineffizienz der Laufzeit. Auch wenn die Funktion add hier zustandslos ist, ist der zurückgegebene Lambda-Typ nicht leer und sein sizeof ist größer als 1 (also boost::function default ctor und copy ctor wird new enthalten). Ich bezweifle wirklich, dass es einen Mechanismus von der Compiler- oder der Boost-Seite gibt, um diese Staatenlosigkeit zu erkennen und Code zu erzeugen, der der Verwendung von:

entspricht %Vor%

Man könnte natürlich c ++ 11 auto verwenden, aber dann kann die Variable nicht um nicht vorlagenbasierte Kontexte weitergegeben werden. Ich habe es schließlich geschafft, fast das zu tun, was ich will, indem ich den folgenden Ansatz benutze:

%Vor%

Kompiliert mit gcc 4.6.1 Die Ausgabe von diesem Programm ist (unabhängig von der Optimierungsstufe):

%Vor%

wie erwartet. Hier behalte ich einen statischen Zeiger auf den Lambda-Ausdruckstyp (so konstant wie möglich für Optimierungszwecke) und initialisiere ihn auf NULL . Auf diese Weise erhalten Sie einen Laufzeitfehler, wenn Sie versuchen, einen Lambda-Ausdruck mit Status zu "statifizieren". Und wenn Sie einen wirklich staatenlosen Lambda-Ausdruck sta- bilisieren, funktioniert alles.

Weiter zu den Fragen:

  1. Die Methode scheint ein wenig dreckig zu sein, können Sie an irgendeinen Umstand oder eine Compiler-Annahme denken, die dieses Fehlverhalten verursachen wird (erwartetes Verhalten: funktioniert gut, wenn Lambda staatenlos ist, sonst segfault).

  2. Können Sie sich vorstellen, dass dies zu einem Compiler-Fehler führt, wenn der Lambda-Ausdruck den Status "?" hat?

EDIT nach Eric Niebler's Antwort:

%Vor%     
enobayram 13.04.2012, 16:46
quelle

1 Antwort

11
  1. Es gibt keine Möglichkeit, das sauberer zu machen. Sie rufen eine Memberfunktion über einen Nullzeiger auf. Das sind alle Arten von undefiniertem Verhalten, aber das weißt du schon.
  2. Sie können nicht wissen, ob eine Boost.Lambda-Funktion zustandslos ist. Es ist eine Blackbox. Boost.Phoenix ist eine andere Geschichte. Es basiert auf Boost.Proto, einem DSL-Toolkit, und Phoenix veröffentlicht seine Grammatik und bietet Ihnen Hooks, um die erzeugten Lambda-Ausdrücke zu überprüfen. Sie können ganz einfach einen Proto-Algorithmus schreiben, um nach statusbehafteten Terminals zu suchen und ihn zur Kompilierzeit auszubomben, wenn er einen findet. (Aber das ändert meine Antwort auf Nr. 1 nicht.)

Sie sagten, Sie mögen die polymorphe Natur von Boosts Lambda-Funktionen, aber Sie verwenden diese Eigenschaft nicht in Ihrem obigen Code. Mein Vorschlag: Verwenden Sie C ++ 11 Lambdas. Die Stateless haben bereits eine implizite Umwandlung in rohe Funktionszeiger. Es ist genau das, wonach Sie suchen, IMO.

=== UPDATE ===

Obwohl das Aufrufen einer Memberfunktion über einen Nullzeiger eine schreckliche Idee ist (tue es nicht, du wirst blind werden), kannst du standardmäßig ein NEU Lambda-Objekt des gleichen Typs des Originals. Wenn Sie das mit meinem Vorschlag in # 2 oben kombinieren, können Sie bekommen, wonach Sie suchen. Hier ist der Code:

%Vor%

Haftungsausschluss: Ich bin nicht der Autor von Phoenix. Ich weiß nicht, ob die Standardkonstruierbarkeit für alle statuslosen Lambdas garantiert ist.

Getestet mit MSVC-10.0.

Viel Spaß!

    
Eric Niebler 07.09.2012, 22:26
quelle