2016-07-27 23 views
20

Sagen, ich habe die folgende Variable ein Lambda enthält:C++ 11 `auto` Lambda zu einem anderen Lambda ändern?

auto a = [] { return true; }; 

Und ich will afalse später zurückzukehren. Könnte ich etwas in diesem Sinne tun?

a = [] { return false; }; 

Diese Syntax gibt mir die folgenden Fehler:

binary '=' : no operator found which takes a right-hand operand of type 
'main::<lambda_a7185966f92d197a64e4878ceff8af4a>' (or there is no acceptable conversion) 

IntelliSense: no operator "=" matches these operands 
     operand types are: lambda []bool()->bool = lambda []bool()->bool 

Gibt es eine Möglichkeit, so etwas zu erreichen? Ich möchte die Variable auto zu einem anderen Lambda ändern. Ich bin ein Anfänger, also kann mir etwas Wissen über auto oder lambdas fehlen. Vielen Dank.

+2

Da ist der 'bool b = wahr; auto a = [& b] {zurück b; }; b = falsch; "Lösung, aber dies verallgemeinert natürlich nicht alle Situationen. – MSalters

Antwort

31

Jeder Lambda-Ausdruck erzeugt einen neuen eindeutigen Typ, daher unterscheidet sich der Typ des ersten Lambda von dem Typ des zweiten Lambda-Typs (example). Außerdem ist der Kopierzuweisungsoperator eines Lambda als gelöscht definiert (example), so dass Sie das doppelt nicht können. Für einen ähnlichen Effekt können Sie haben a ein std::function Objekt sein, obwohl es Ihnen einige Performance kosten würde

std::function<bool()> a = [] { return true; }; 
a = [] { return false; }; 
32

A Lambda kann auf einen Funktionszeiger mit dem unäre + Operator wie so umgewandelt werden:

+[]{return true;} 

solange die Erfassungsgruppe leer ist und keine auto Argumente hat.

Wenn Sie dies tun, können Sie der gleichen Variablen verschiedene Lambdas zuweisen, solange die Lambdas alle dieselbe Signatur haben.

In Ihrem Fall

Live example on Coliru

würden beide kompilieren und zu handeln wie Sie es erwarten. Sie können die Funktionszeiger auf dieselbe Weise verwenden, wie Sie erwarten würden, ein Lambda zu verwenden, da beide als functors fungieren.


1. In C++ 14, können Sie lambdas mit auto als Argument Typ, wie [](auto t){} erklären. Diese sind generic lambdas und haben eine Vorlage operator(). Da ein Funktionszeiger keine Vorlagenfunktion darstellen kann, funktioniert der Trick + nicht mit generischen Lambdas.

2. Technisch benötigen Sie nicht den zweiten Operator + auf der Zuordnung. Das Lambda würde bei Zuweisung in den Funktionszeigertyp umgewandelt. Ich mag die Konsistenz jedoch.

+10

Der Moment, als C++ offiziell in den Perl-Bereich eingetreten ist! – peppe

+0

@jaggedSpire Ich habe das so oft gebraucht, und ich dachte, die einzige Lösung wären die anderen 'Funktions'-Antworten auf diese Frage. Wie hast du das herausgefunden? Ich habe es noch nie zuvor gesehen. –

+0

@JonathanMee Ich fand es tatsächlich von einem verwandten Link in der Sidebar, einmal: [Ein positives Lambda: '+ [] {}' - Was ist das für eine Zauberei?] (Http://stackoverflow.com/questions/18889028) – jaggedSpire

4

Jedes Lambda hat einen anderen Typ, so dass Sie es nicht ändern können. Sie können eine std::function verwenden, um ein beliebiges aufrufbares Objekt zu halten, das beliebig geändert werden kann.

std::function <bool()> a = [] { return true; }; 
a = [] { return false; }; 
+0

Ich denke, Ryan hat dich dazu gebracht, dasselbe zu veröffentlichen. Aber du verpasst ein Semikolon. –

1

können wir retrospective call verwenden Lambda zu konvertieren :: Funktion std:

template<typename T> 
struct memfun_type 
{ 
    using type = void; 
}; 

template<typename Ret, typename Class, typename... Args> 
struct memfun_type<Ret(Class::*)(Args...) const> 
{ 
    using type = std::function<Ret(Args...)>; 
}; 

template<typename F> 
typename memfun_type<decltype(&F::operator())>::type 
FFL(F const &func) 
{ // Function from lambda ! 
    return func; 
} 

Danach wir in der Lage zu (da 'a' std :: function Typ jetzt):

auto a = FFL([] { return false; }); 
a = FFL([] { return true; }); 
+0

Ein bisschen mehr Erklärung wäre nett gewesen. –

0

Seit C++17 können Sie die std::function Template-Parameter dank Class template argument deduction abgeleitet haben. Es funktioniert sogar mit der Erfassung von Lambdas:

Dies ist nützlich mit komplexeren Signaturen und noch mehr mit abgeleiteten Rückgabetypen.