2013-05-24 10 views
5

Diese Frage ist eine Fortsetzung einer aktuellen Frage von mir:
What is this compiler error when using a lambda as a template parameter?
Lambda zurückkehrendes Lambda führt fälschlicherweise Rückkehrtyp?

11 Nov., 2014 Microsoft hat das Update für diesen Fehler reagiert sagen sollte ++ in der nächsten Hauptversion von Visual C angezeigt.


Dieser Code die VS2012 mit (Update 2) zu kompilieren, schlägt fehl:

1> main.cpp 
1>C:\test\main.cpp(7): error C2440: 'return' : cannot convert from 'main::<lambda_c5d1d707b91a1ddedc06eb080503550c>::()::<lambda_ac357c309731f4971c3269160ed9c24b>' to 'int (__cdecl *)(void)' 
1>   No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 

  • :

    int main(int argc, char* argv[]) 
    { 
        auto f = []() 
        { 
         int n = 0; 
         auto r = [=]{ return n; }; 
         return r; 
        }; 
        return 0; 
    } 
    

    ich Dies ist der Compiler-Fehler Gibt es ein Problem mit dem Code nach C++ 11 Spezifikation?

  • Gibt es ein Problem mit dem Code gemäß VS2012 definierten partiellen C++ 11 Unterstützung?
  • Oder ist das ein VS2012 C++ Compiler Bug?

  • Könnte mir jemand an den Ort Punkt in der C++ 11-Spezifikation, die darüber spricht, wie Lambda-Ausdrücke zu Funktionszeiger implizit umsetzbar sein muss?
    • Ich erinnere mich an diese nur für staatenlos lambdas sein - jene mit leeren capture Klauseln - die die innere Lambda r ist nicht
    • Also warum es scheint, dass die abgeleitete Rückgabetyp von Lambda f eine Funktion ist Zeiger, nämlich int (__cdecl *)(void)?
+0

Lassen Sie uns sagen, dass es wegen einer schlechten ist Implementation :-) –

+1

@CaptainObvlious Okay - aber der Cast zu Funktion Zeiger ist explizit * nicht erlaubt * für * Stateful * Lambdas, richtig? –

+0

[Unsicher, wie _ "nicht" _ in meinen früheren Kommentar kam - sorry;)] Nach 5.1.2/6 ist die Konvertierung _is_ erforderlich, wenn sie nicht erfasst wird. Der Standard verbietet jedoch nicht ausdrücklich, dass die Umwandlung für statusbehaftete Lambdas berücksichtigt wird. Mein Verständnis ist, da es _unspecified_ ist, ist die Implementierung frei, die Umwandlung sogar für stateful lambdas einzuschließen. –

Antwort

2

Obwohl GCC 4.7.2 diesen Code kompiliert es schlecht gebildet wird. Der Lambda-Ausdruck, der f initialisiert, ist zu komplex, um den Rückgabetyp abzuleiten. Tatsächlich 5.1.2/4 sagt

Wenn ein Lambda-Ausdruck keinen abschließenden-Return-Typen enthält, ist es, als ob der Hinterrückgabetyp den folgenden Typ bezeichnet:

- wenn die Verbindung-Anweisung hat die Form

{ attribute-specifier-seq[opt] return expression ; } 

die Art der zurück Expression nach lvalue-zu-R-Wert-Umwandlung (4.1), array-zu-Zeiger-Umwandlung (4.2), und die Funktion-zu-Zeigern Umwandlung (4.3);

- sonst, void.

Daher wird in diesem Beispiel der Rückgabetyp ist void aber die Lambda etwas anderes zurückkehrt. Der Code sollte nicht kompiliert werden.

Ich stimme zu, dass die von Visual Studio ausgegebene Nachricht irreführend ist.

aktualisieren: Auf dieser Frage

So wäre es richtig zu sagen: "In C++ 11, können Sie kein Lambda definieren, die ein Stateful-Lambda gibt"?

No. Gemäß dem C++ 11 Zitat unten, die Art von einem Lambda zurück ist void, wenn der Körper des Lambdas enthält nur eine einzige Leitung mit einem return expression;. Wenn Sie also Ihr statusbehaftetes Lambda in einem Rückgabeausdruck erstellen, ist das in Ordnung. Zum Beispiel stellt der folgende Code in GCC 4.7.2, Clang 3.2 und Intel Compiler 13.1.0: (Es kompiliert nicht in VS2012 aufgrund der oben genannten Fehler.)

#include <iostream> 

int main() { 
    int n = 5; 
    auto f = [=] { 
     return [=]{ return n; }; // creates a stateful lambda and returns it in a single line 
    }; 
    std::cout << f()() << std::endl; 
    return 0; 
} 
+0

"Daher ist in diesem Beispiel der Rückgabetyp" void ". .. " - Das stimmt nicht mit dem überein, was der Compiler sagt. Der Compiler sagt, dass der Rückgabetyp "int (__cdecl *) (void)" ist. Außerdem sagt es, dass es nicht in der Lage ist, die Umwandlung vom Lambda-Typ in der Zeile "auto r = ...;" in den Rückgabetyp von "f" zu übernehmen, was "int (__cdecl *) (void)" ist . Korrigiere mich, wenn ich falsch liege, weil ich irgendwie verwirrt bin. :) –

+0

@TimothyShields: GCC ist falsch, den Code als C++ 11 zu akzeptieren (für C++ 14 CD ist es aber korrekt). Visual Studio hat recht, wenn es den Code nicht akzeptiert, aber aus dem falschen Grund: Es sollte nicht versuchen, ein statusbehaftetes Lambda in einen Funktionszeiger umzuwandeln. –

+0

Könnten Sie Ihre Gedanken zu dieser mir kürzlich gestellten Frage mitteilen? Ich denke, die Antworten, die ich dort bekommen habe, waren möglicherweise aufgrund Ihrer Einsichten falsch. http://stackoverflow.com/questions/16661981/what-is-this-compiler-error-when-using-a-lambda-as-a-template-parameter –

Verwandte Themen