Was ist die Typ-Signatur einer C ++ 11 / 1y-Lambda-Funktion?

9

Ich frage mich, ob es einen Standardweg gibt, um die Typ-Signatur (d. h. den Rückgabetyp und die Typen) ihrer Parameter irgendeines gegebenen Lambda zu erhalten?

Der Grund warum ich frage ist, dass ich mich immer gefragt habe, was genau der Typ auto in der Deklaration ist wie auto l =[](int x,int y)->int{return x+y;} . In anderen Anwendungsfällen von auto ist es eine bequeme und kürzere Alternative für einen längeren Typnamen. Aber gibt es für Lambdas sogar eine alternative Möglichkeit, die Lambda-Variable zu deklarieren?

Nach meinem Verständnis ist ein Standard-Lambda nichts anderes als ein Funktionsobjekt, und es ist sein eigener Typ. Selbst wenn zwei Lambdas denselben Rückgabetyp und Parametertyp haben, sind sie immer noch zwei verschiedene, nicht verwandte Klassen / Funktoren. Aber gibt es einen Weg, um die Tatsache zu erfassen, dass sie in Bezug auf Typensignatur identisch sind?

Ich denke, die Typensignatur, nach der ich suche, kann etwas wie ein std::function<> Objekt der richtigen Typen sein.

Eine nützlichere / beteiligtere Frage ist, wenn es möglich ist, die Typ-Signatur zu extrahieren, ist es möglich, eine allgemeine Wrapper-Funktion zu schreiben, um jede Lambda-Funktion in ein std::function -Objekt der gleichen Typsignatur umzuwandeln.

    
tinlyx 09.02.2014, 09:53
quelle

4 Antworten

11

Nach Kann der "Typ" Wird ein Lambda-Ausdruck ausgedrückt? , es gibt tatsächlich einen einfachen Weg im aktuellen C ++ (ohne C ++ 1y), um den return_type und die Parametertypen eines Lambda herauszufinden. Wenn Sie dies anpassen, ist es nicht schwierig, für jedes Lambda einen std::function typisierten Signaturtyp (nachfolgend f_type genannt) zu erstellen.

Ich. Mit diesem abstrakten Typ ist es tatsächlich möglich, einen alternativen Weg zu auto zu haben, um die Typ-Signatur eines Lambda, nämlich function_traits<..>::f_type , auszudrücken. Hinweis: Das f_type ist nicht der reale Typ eines Lambda, sondern eine funktionale Zusammenfassung der Lambdasignatur. Es ist jedoch wahrscheinlich nützlicher als der reale Typ eines Lambda, weil jedes einzelne Lambda sein eigener Typ ist.

Wie im folgenden Code gezeigt, kann man auch vector<int>::iterator_type i = v.begin() verwenden, genauso wie man function_traits<lambda>::f_type f = lambda benutzen kann. Dies ist eine Alternative zum mysteriösen auto . Natürlich ist diese Ähnlichkeit nur formal. Der folgende Code beinhaltet die Konvertierung des Lambda in std::function mit den Kosten für das Löschen des Typs bei der Erstellung des Objekts std::function und eine geringe Kosten für den indirekten Aufruf über das Objekt std::function . Aber diese Implementierungsprobleme bei der Verwendung von std::function side (was ich nicht für fundamental halte und für immer stehen sollte), ist es doch möglich, die (abstrakte) Typ-Signatur eines gegebenen Lambda explizit auszudrücken.

II. Es ist auch möglich, einen make_function wrapper (ähnlich wie std::make_pair und std::make_tuple ) zu schreiben, um automatisch ein Lambda f (und andere callables wie Funktionszeiger / Funktoren) in std::function mit demselben Typ zu konvertieren -deduction Fähigkeiten.

Testcode ist unten:

%Vor%     
tinlyx 09.02.2014, 22:07
quelle
10

Sie haben Korrekt die Typen von C ++ 11 Lambdas sind anonym und instance-unique. Der std::function -Typ kann Verweise auf jede Art von Lambda speichern, die mir begegnet sind, aber es wird gesagt, dass es ein Performance-Hit ist.

Versuchen Sie

%Vor%

Beachten Sie, dass die -> int in nicht mehrdeutigen Szenarien wie diesem weggelassen werden kann.

C ++ 14 lässt uns schreiben

%Vor%

ist nützlich für lange Typnamen.

Wie von @ Jonathan Wakely festgestellt, erfasst dieser Ansatz eine bestimmte Instanziierung mit std :: function mit festen Vorlagenargumenten. In C ++ 14 können Template-Variablen angegeben werden. Zusätzlich können auch nach C ++ 14 Lambda-Parameter ihre Typen über auto ableiten lassen, wobei folgendes gilt:

%Vor%

Gegenwärtig scheinen VC ++ und GCC keine Vorlagen für Variablendeklarationen auf Funktionsebene zu unterstützen, sondern sie für Member-, Namespace- und globale Deklarationen zuzulassen. Ich bin mir nicht sicher, ob diese Einschränkung aus der Spezifikation hervorgeht.

Hinweis: Ich benutze keinen Klang.

    
Aluan Haddad 09.02.2014 09:59
quelle
2

In C ++ 1y gibt es generische Lambdas und keine Signatur für einzelne Aufrufe ( operator()() ist eine Vorlage).

    
Ben Voigt 09.02.2014 10:01
quelle
1
  

Ich habe mich gefragt, ob es eine Standardmethode gibt, um die Typ-Signatur (d. h. den Rückgabetyp und die Typen) ihrer Parameter eines gegebenen Lambda zu erhalten?

Nein, gibt es nicht.

  

Der Grund warum ich frage ist, dass ich mich immer gefragt habe, was genau der Typ auto in der Deklaration ist wie auto l =[](int x,int y)->int{return x+y;} .

Es ist ein unspezifizierter Klassentyp, der von der Implementierung erstellt wurde. Der ganze Sinn von Lambdas ist, dass sie "anonyme Funktionen" sind, d. H. Sie kennen ihren Typ nicht.

Wenn Sie einen bekannten Typ haben wollen, dann schreiben Sie einen Funktionsobjekttyp.

  

In anderen Anwendungsfällen von Auto ist es eine bequeme und kürzere Alternative für einen längeren Typnamen. Aber gibt es für Lambdas sogar eine alternative Möglichkeit, die Lambda-Variable zu deklarieren?

Nein.

Wenn Sie den Typ selbst deklarieren möchten, verwenden Sie keinen Lambda-Ausdruck.

  

Nach meinem Verständnis ist ein Standard-Lambda nichts anderes als ein Funktionsobjekt, und es ist sein eigener Typ. Selbst wenn zwei Lambdas den gleichen Rückgabetyp und Parametertyp haben, sind sie immer noch zwei verschiedene, nicht verwandte Klassen / Funktoren.

Richtig. Jeder Lambda-Ausdruck erzeugt einen eindeutigen Typ.

  

Aber gibt es einen Weg, um die Tatsache zu erfassen, dass sie in Bezug auf Typensignatur identisch sind?

Nein, es gibt keine Sprachfunktion, die das erlaubt.

  

Ich denke, die Typensignatur, nach der ich suche, kann etwas wie eine std :: function & lt; & gt; Objekt der richtigen Typen.

Selbst wenn es in C ++ 11 möglich war, würde es in C ++ 14 nicht helfen, wo Lambda-Ausdrücke irgendeine Zahl und jede Art von Argument annehmen können, z. [](auto... a) { }

Und wenn Sie die Call-Signatur Ihrer Lambda-Funktion nicht kennen, dann würde ich sagen, dass Sie lambdas falsch verwenden. Wenn Sie das Lambda schreiben, sollten Sie wissen, was seine Eigenschaften sind, also verwenden Sie es entweder sofort oder fügen Sie es in ein std::function (oder einen anderen Typ, der seine Call Signatur erfasst) so früh wie möglich ein, wenn Sie seine Eigenschaften kennen. Wenn Sie Lambdas erstellen und sie nicht lokal verwenden, wo Sie die Signatur nicht kennen, tun Sie es falsch.

    
Jonathan Wakely 09.02.2014 14:47
quelle

Tags und Links