Cast lambda to std :: Funktion mit Parameterpack

8

Es gibt einige Fragen zu SO, die sich auf das Casting von Lambdas auf std::function s beziehen, aber ich muss noch eines sehen, das ein Parameter-Pack für die Argumentliste verwendet. Das scheint bei meiner Version von g ++ (7.1.1-4) kaputt zu sein, und möglicherweise wird es einfach nicht unterstützt. Also ist das legal c ++ 17 (im Standard)? Wenn nicht, warum?

%Vor%

Der obige Code wird nicht kompiliert, weil die Typableitung fehlschlägt. Offensichtlich macht das explizite Eingeben von x als std::function<int (int, int)> anstelle von auto den Fehler weg. Aber das erlaubt mir nicht, einen r-Wert an Functor zu übergeben, wie ich es möchte. Ich möchte auch keine Typsicherheit verlieren, indem ich einen anderen Template-Parameter für den Funktionstyp verwende.

Was ich wirklich nicht verstehe ist, warum der obige Code nicht kompiliert werden kann, aber der folgende Code ist in Ordnung und funktioniert:

%Vor%     
Howard 21.07.2017, 19:47
quelle

4 Antworten

10

Das Problem ist, dass der Compiler nicht weiß, dass int, int die Gesamtheit von TArgs sein soll, und versucht daher, den Rest von TArgs vom Argument f abzuleiten.

Dies wäre beispielsweise gültig:

%Vor%

Sie müssen also den Compiler anweisen, nicht den Rest von TArgs abzuleiten. Zum Beispiel könnten Sie schreiben:

%Vor%

Oder Sie könnten Functor mit einer nicht zerlegten Signatur Sig :

schreiben %Vor%

Oder Sie könnten die Verwendung von TArgs im Parameter f in einem nicht-abgeleiteten Kontext umbrechen:

%Vor%     
ecatmur 21.07.2017, 20:00
quelle
6

Dies schlägt fehl:

%Vor%

, weil Sie nicht angeben, dass die Gesamtheit von TArgs... {int, int} ist. Sie geben an, dass die ersten beiden Typen {int, int} sind. Wenn wir diese drei Typen zur Verfügung stellen, haben wir das Deduktionsproblem effektiv in folgendes umgewandelt:

%Vor%

Dies wird nicht kompiliert, weil ein Lambda kein std::function ist (oder von eins abgeleitet ist), was der gleiche Grund ist, warum Sie dies nicht aufgerufen haben könnten, ohne irgendwelche Typen bereitgestellt zu haben.

Die nicht-variadische Version hat dieses Problem nicht, da Sie alle Typen bereitgestellt haben.

Aber wirklich, was Sie wollen, ist:

%Vor%

Damit verlieren Sie keine Sicherheit. Es verwendet std::function , das Typinformationen verliert, da diese Klassenvorlage zum Eingeben von Erase existiert.

    
Barry 21.07.2017 20:00
quelle
2

Es ist sehr selten eine gute Idee, ein Lambda auf ein std::function in einem template zu setzen, wenn Sie es einfach aufrufen. std::function ist type-erasure, und das Löschen von Templates ist nur dann sinnvoll, wenn Sie es "woanders weitergeben" und / oder zurückgeben.

Versuchen Sie es auf jeden Fall:

%Vor%

Aber du solltest es wirklich tun

%Vor%

was perfekt typsicher ist.

Wenn Sie eine frühe Typprüfung wünschen, könnten Sie

schreiben %Vor%

tue es dann

%Vor%

aber nur, wenn Sie wirklich brauchen.

    
Yakk 21.07.2017 20:15
quelle
0

Hier ist eine Lösung, mit der Sie functor aufrufen können, ohne das Template-Argument anzugeben:

%Vor%

Dies ist nur ein fauler erster Entwurf für den Einstieg. Sie müssen es erweitern, um die Weiterleitung und nicht-const operator() zu unterstützen.

Es funktioniert in 2 Stufen:

1. Wir haben Fun_trait who - für Zeiger-Methodentypen (z. B. die operator() eines Lambda) - einen Alias F für den erforderlichen std::function -Argumenttyp definiert.

Als nächstes haben wir eine Überladung Ihrer Funktion functor , die über SFINAE mit std::void_t nur für Funktoren mit einem nicht überladenen operator() (zB ein Lambda) eintritt und dann die oben genannte Eigenschaft verwendet, ruft die Hauptfunktion% auf. co_de% mit dem korrekten Template-Argument abgeleitet.

    
bolov 21.07.2017 20:08
quelle