2013-05-24 20 views
5

To pytanie jest kontynuacją ostatniej kwestii kopalni:
What is this compiler error when using a lambda as a template parameter?
Lambda zwracająca lambdę nieprawidłowo podaje typ zwrotu?

11 listopada 2014: Microsoft zareagował mówiąc, że poprawka do tego błędu powinno pokazać się w następnej wersji Visual C++.


Ten kod nie skompilować za pomocą VS2012 (Update 2):

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

Jest to błąd kompilatora uzyskać:

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 

  • Jest jakiś problem z kodem zgodnym ze specyfikacją C++ 11?
  • Czy występuje problem z kodem zgodnie ze zdefiniowaną przez VS2012 częściową obsługą C++ 11?
  • A może to błąd kompilatora VS2012 C++?

  • Może ktoś mi punkt do miejsca w specyfikacji C++ 11, który mówi o tym, jak lambda musi być niejawnie rzutować do wskaźników funkcji?
    • wspominam ten jest tylko dla bezpaństwowców lambdas - tych z klauzulami pustych przechwytywania - co wewnętrzna lambda r jest nie
    • Dlaczego więc wydaje się, że wywnioskować typ zwracany lambda f jest funkcją wskaźnik, a mianowicie int (__cdecl *)(void)?
+0

Powiedzmy, że to z powodu słabego implementacja :-) –

+1

@CaptainObvlious Okay - ale rzutowanie na wskaźnik funkcji jest jawnie * zabronione * dla * stateful * lambdas, prawda? –

+0

[Nie jestem pewien, jak _ "nie" _ wpadł w mój wcześniejszy komentarz - przepraszam;)] Zgodnie z 5.1.2/6 konwersja _jest_ wymagana, jeśli nie ma przechwycenia. Standard nie wyklucza jednak jawnie, że konwersja nie została uwzględniona dla stanów lambdas. Moje zrozumienie jest takie, że nie jest możliwe, aby implementacja mogła uwzględniać konwersję nawet dla stanów lambd. –

Odpowiedz

2

Chociaż GCC 4.7.2 kompiluje ten kod, to jest źle sformułowany. Wyrażenie lambda, które inicjuje f jest zbyt skomplikowane, aby wydedukować typ zwracany. Rzeczywiście, 5.1.2/4 mówi

Jeżeli lambda ekspresji nie zawiera zwrotny typu wleczonego, to jest tak, że zwrotny typu wleczonego oznacza typu:

- jeżeli związek instrukcja_select ma postać

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

typu zwróconej ekspresji w lwartości do rValue konwersji (4.1), macierz-to-wskaźnika konwersji (4.2), a funkcja do wskaźnika konwersja (4.3);

- w przeciwnym razie nieważne.

Dlatego w tym przykładzie typ zwracany jest void ale lambda wraca coś innego. Kod nie powinien się kompilować.

Zgadzam się, że wiadomość przekazana przez Visual Studio jest myląca.

Aktualizacja: Na to pytanie

Więc byłoby poprawne powiedzieć "w C++ 11, nie można zdefiniować lambda, która zwraca pełnostanowego lambda"?

nr Zgodnie C++ 11 środki poniżej, rodzaj zwracane przez lambda void jeżeli korpus lambda zawiera tylko jedną linię o return expression;. Dlatego jeśli uda ci się stworzyć twoją stateful lambda w wyrażeniu zwrotnym, to jest w porządku. Na przykład, poniższy kod kompiluje w GCC 4.7.2, 3.2 i Intel Clang kompilator 13.1.0: (To nie skompilować w VS2012 z powodu wspomnianego błędu.)

#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

"Dlatego w tym przykładzie typem zwracanym jest' void'. ... " - to nie jest zgodne z tym, co mówi kompilator. Kompilator mówi, że typem zwracanym jest 'int (__cdecl *) (void)'. Ponadto mówi się, że nie jest w stanie wykonać konwersji z typu lambda w linii 'auto r = ...;' na typ zwracający 'f', który jest' int (__cdecl *) (void) ' . Popraw mnie, jeśli się mylę, bo jestem trochę zdezorientowany. :) –

+0

@ TimothyShields: GCC nie zgadza się z zaakceptowaniem kodu jako C++ 11 (dla C++ 14 CD jest to jednak poprawne). Visual Studio ma rację, nie akceptując kodu, ale z niewłaściwego powodu: nie powinien próbować konwertować stanu lambda na wskaźnik funkcji. –

+0

Czy możesz podzielić się swoimi przemyśleniami na temat tego ostatniego pokrewnego pytania? Myślę, że odpowiedzi, które tam uzyskałem, mogły być nieprawidłowe w oparciu o twoje spostrzeżenia. http://stackoverflow.com/questions/16661981/what-is-this-compiler-error-when-using-a-ambambda-as-a-plateplate-parameter –

Powiązane problemy