Irgendeine Idee, warum das folgende Snippet nicht kompiliert wird? Es beschwert sich mit einem Fehler "Fehler: Operanden zu ?: Haben verschiedene Typen"
Einzelne Lambdas werden vom Compiler in verschiedene Klassen übersetzt. Zum Beispiel entspricht die Definition von lambda1:
classSomeCompilerGeneratedTypeName{public:SomeCompilerGeneratedTypeName(...){// Capture all the required variables here}voidoperator()(T& arg)const{// ...}private:// All the captured variables here ...};
Daher werden vom Compiler zwei verschiedene Typen generiert, was zu einer Typinkompatibilität für führt auto lambda = condition ? lambda1 : lambda2;
Folgendes würde funktionieren:
auto lambda = condition ? std::function<void(T&)>(lambda1): std::function<void(T&)>(lambda2);
Um hervorzuheben, dass beide Lambdas tatsächlich unterschiedliche Typen sind, können wir sie <typeinfo>aus der Standardbibliothek und dem typeidOperator verwenden. Lambdas sind keine polymorphen Typen, daher garantiert der Standard, dass der Operator 'typeid' zur Kompilierungszeit ausgewertet wird. Dies zeigt, dass das folgende Beispiel auch dann gültig ist, wenn RTTI deaktiviert ist:
Vollständiger Fehler ist "Fehler: Operanden zu ?: Haben verschiedene Typen 'f (const std :: vector <int> &, size_t, size_t) [mit T = vorzeichenloses Zeichen; size_t = lang vorzeichenloses int] :: <lambda (vorzeichenloses Zeichen & )> 'und' f (const std :: vector <int> &, size_t, size_t) [mit T = vorzeichenloses Zeichen; size_t = lang vorzeichenloses int] :: <lambda (vorzeichenloses Zeichen &)> '", in dem ich sehe identisch alle Typen & Formate.
Kuh
1
@cow Da das Lambda an sich dieselbe Signatur hat, gibt Ihnen der Compiler, um seine Implementierungsdetails zu verbergen und einen verständlicheren Fehler zu geben, den Speicherort und die Signatur beider Lambdas, die identisch sind. Aber am Ende werden sie immer noch als SomeCompilerGeneratedTypeName1und interpretiertSomeCompilerGeneratedTypeName2
Xatyrian
1
@cow Ich habe ein Beispiel hinzugefügt, das den Anfang der Antwort hervorhebt. Vielleicht finden Sie es interessant
Xatyrian
12
Seltsamerweise +kann ein Operator- Trick angewendet werden , wenn Lambdas ohne Erfassung sind :
auto lambda1 =[](int arg){...};auto lambda2 =[](int arg){...};auto lambda = condition ?+lambda1 :+lambda2;// This compiles!
lambda(2019);
Das funktioniert, weil + Lambda in einen Funktionszeiger konvertiert wird und beide Funktionszeiger denselben Typ haben (so etwas wie void (*)(int)).
Wenn GCC und Clang (aber nicht MSVC) +weggelassen werden können, werden Lambdas weiterhin in Funktionszeiger konvertiert.
Dies funktioniert jedoch nicht in Visual Studio. Ihre Erweiterung, die es einem Lambda ermöglicht, in eine andere Anrufkonversion umzuwandeln, verhindert dies.
Guillaume Racicot
@ GuillaumeRacicot, danke für diesen Hinweis. Könnten Sie bitte einen Link angeben, über den ich mehr darüber lesen kann?
Da 2 Lambdas ( lambda1und lambda2) 2 verschiedene Typen sind, ?:kann der Rückgabetyp für nicht abgeleitet werdenlambda aus lambda1und lambda2. Dies geschieht, weil diese 2 nicht ineinander konvertierbar sind.
SomeCompilerGeneratedTypeName1
und interpretiertSomeCompilerGeneratedTypeName2
Seltsamerweise
+
kann ein Operator- Trick angewendet werden , wenn Lambdas ohne Erfassung sind :Das funktioniert, weil
+
Lambda in einen Funktionszeiger konvertiert wird und beide Funktionszeiger denselben Typ haben (so etwas wievoid (*)(int)
).Wenn GCC und Clang (aber nicht MSVC)
+
weggelassen werden können, werden Lambdas weiterhin in Funktionszeiger konvertiert.quelle
Der Compiler kann nicht entscheiden, welcher Typ
auto
sein soll:da jedes Lambda einen anderen und einzigartigen Typ hat.
Ein Weg, der funktionieren wird, ist:
quelle
Es wird nicht kompiliert, da jedes Lambda einen eindeutigen Typ hat. Es gibt keinen gemeinsamen Typ für
?:
.Sie könnten sie einwickeln
std::function<void(T&)>
, zquelle
Da 2 Lambdas (
lambda1
undlambda2
) 2 verschiedene Typen sind,?:
kann der Rückgabetyp für nicht abgeleitet werdenlambda
auslambda1
undlambda2
. Dies geschieht, weil diese 2 nicht ineinander konvertierbar sind.quelle