2009-03-23 5 views
3

Ich habe eine Funktion der Form:Boost Lambda-Sammlung Größe Auswertung

void DoSomething(const boost::function<bool()>& condition, other stuff); 

Diese Funktion führt einige Schritte und gibt nur dann, wenn die Bedingung erfüllt ist. Die Bedingung wurde als Funktorargument ausgedrückt, da ich an verschiedenen Aufruforten unterschiedliche Bedingungen liefern möchte.

Nun ist es ziemlich einfach direkt zu verwenden, aber es erfordert viele kleine Wegwerffunktionen oder Funktorobjekte zu deklarieren, die ich wenn möglich vermeiden möchte. Ich habe in Boosts Lambda-Bibliothek nach möglichen Möglichkeiten gesucht, diese zu beseitigen, aber ich denke, dass ich etwas Grundlegendes vermisse; Ich kann es einfach nicht tun, was ich will.

Ein Fall, der mich im Moment ratlos ist: Ich habe eine std::vector Sammlung namens data; Die Bedingung, dass ich bin, ist, wenn die size() dieser Sammlung einen bestimmten Schwellenwert erreicht. Im Wesentlichen möchte ich dann, dass mein condition-Funktor wahr zurückgibt, wenn data.size() >= threshold und andernfalls falsch sind. Aber ich habe Probleme, dies in Lambda-Syntax auszudrücken.

Das Beste, was ich in der Lage habe mit so weit zu kommen (was zumindest kompiliert, obwohl es nicht funktioniert), ist dies:

boost::function<bool (size_t)> ge = boost::bind(std::greater_equal<size_t>(), 
               _1, threshold); 
boost::function<size_t()> size = boost::bind(&std::vector<std::string>::size, 
               data); 
DoSomething(boost::lambda::bind(ge, boost::lambda::bind(size)), other stuff); 

Beim Eintritt in DoSomething die Größe 0 - und obwohl die Größe im Laufe des Laufens zunimmt, scheinen die Aufrufe an condition() immer eine Größe von 0 zu bekommen. Tracing durch (was ein wenig knifflig durch Boosts Interna ist), während es scheint, greater_equal jeweils zu rufen Zeit condition() wird ausgewertet, es scheint nicht size() aufrufen.

Also, welche grundlegende Sache habe ich komplett vermasselt? Gibt es eine einfachere Art, solche Dinge auszudrücken (während der Code immer noch so inline wie möglich ist)?

Ich würde am liebsten so nahe wie möglich an der C# -Äquivalent Code Geläufigkeit erhalten:

DoSomething(delegate() { return data.size() >= threshold; }, other stuff); 
DoSomething(() => (data.size() >= threshold), other stuff); 

Antwort

5

Das Problem ist, dass die Lambda-Funktion eine Kopie des data Vektor speichert, keine Referenz. So wird size() auf der Kopie aufgerufen, nicht das ursprüngliche Objekt, das Sie ändern. Dies kann durch Umwickeln data mit boost::ref gelöst werden, die eine Referenz speichert stattdessen:

boost::function<size_t()> size = boost::bind(&std::vector<std::string>::size, 
               boost::ref(data)); 

Sie können auch den normalen >= Operator statt std::greater_equal<> in der Definition Ihrer Lambda-Funktion nutzen und kombinieren sie alle zusammen:

boost::function<bool()> cond = 
    (boost::bind(&std::vector<std::string>::size, boost::ref(data)) 
     >= threshold); 

DoSomething(cond, other stuff); 
+0

Danke, das hat funktioniert. Obwohl es für mich überraschend ist, dass man> = so auf eine gebundene Funktion anwenden kann - zumal es nicht einmal die Lambda-Bindung ist! :) – Miral

+0

Das> = ist für das Funktionsobjekt überladen, aber vielleicht wäre boost :: lambda :: bind sowieso eine bessere Wahl ... – sth