2013-05-24 35 views
5

Câu hỏi này là sự tiếp nối của một câu hỏi gần đây của tôi:
What is this compiler error when using a lambda as a template parameter?
Lambda trở về lambda không chính xác infers loại trở lại?

11 Tháng 11 2014: Microsoft đã trả lời rằng việc sửa chữa cho lỗi này nên xuất hiện trong bản phát hành lớn tiếp theo của Visual C++.


Mã này thất bại trong việc biên dịch bằng cách sử dụng VS2012 (Cập nhật 2):

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

Đây là lỗi biên dịch tôi nhận được:

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 

  • Có vấn đề gì không với mã theo đặc điểm kỹ thuật C++ 11?
  • Có sự cố với mã theo sự hỗ trợ một phần C++ 11 đã xác định của VS2012 không?
  • Hoặc đây có phải là lỗi trình biên dịch C++ VS2012 không?

  • Có thể ai đó cho tôi điểm diễn ra trong C++ 11 đặc điểm kỹ thuật mà nói về cách lambdas phải ngầm bột nhôm để con trỏ chức năng?
    • tôi nhớ lại điều này chỉ là cho stateless lambdas - những người có khoản chụp rỗng - đó lambda nội rkhông
    • Vì vậy, tại sao nó xuất hiện rằng kiểu trả về suy ra của lambda f là một chức năng con trỏ, cụ thể là int (__cdecl *)(void)?
+0

Giả sử nó là do người nghèo thực hiện :-) –

+1

@CaptainObvlious Được rồi - nhưng việc truyền tới con trỏ hàm là rõ ràng * không được phép * đối với * stateful * lambdas, đúng không? –

+0

[Không chắc chắn làm thế nào _ "không" _ nhận vào bình luận trước đó của tôi - xin lỗi;)] Theo 5.1.2/6 chuyển đổi _is_ yêu cầu nếu nó không có nắm bắt. Các tiêu chuẩn không _explicitly_ cấm chuyển đổi từ được bao gồm cho lambdas stateful mặc dù. Sự hiểu biết của tôi là vì nó đã được xác định_ việc triển khai thực hiện miễn phí bao gồm chuyển đổi ngay cả đối với các lambdas trạng thái. –

Trả lời

2

Mặc dù GCC 4.7.2 biên dịch mã này bị ốm. Biểu thức lambda khởi tạo f quá phức tạp để loại bỏ kiểu trả về. Thật vậy, 5.1.2/4 nói

Nếu một lambda-biểu hiện không bao gồm một dấu-trở-type, nó là, nếu như dấu-trở-type biểu thị các loại sau đây:

- nếu hợp chất-tuyên bố có dạng

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

kiểu của biểu thức trở lại sau khi giá trị trái-to-rvalue chuyển đổi (4.1), mảng-to-con trỏ chuyển đổi (4.2), và chức năng-to-con trỏ chuyển đổi (4.3);

- nếu không, sẽ bị vô hiệu.

Vì vậy, trong ví dụ này kiểu trả về là void nhưng lambda lại trả về thứ khác. Mã không được biên dịch.

Tôi đồng ý rằng thông báo do Visual Studio đưa ra là gây hiểu lầm.

Cập nhật: Về câu hỏi này

Vì vậy, nó sẽ là đúng khi nói "Trong C++ 11, bạn không thể định nghĩa một lambda mà trả về một lambda stateful"?

số Theo C++ 11 trích dẫn dưới đây, kiểu trả về bởi một lambda là void trừ khi cơ thể của lambda chứa chỉ một dòng duy nhất với một return expression;. Do đó, nếu bạn quản lý để tạo lambda stateful của bạn trong một biểu thức trở lại, thì điều này là tốt. Ví dụ, mã dưới đây biên dịch trong GCC 4.7.2, Clang 3.2 và trình biên dịch Intel 13.1.0: (Nó không biên dịch trong VS2012 do lỗi nói trên.)

#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

"Vì vậy, trong ví dụ này kiểu trả về là' void'. .. " - đó là không phù hợp với những gì trình biên dịch nói. Trình biên dịch nói kiểu trả về là 'int (__cdecl *) (void)'. Hơn nữa, nó nói rằng nó không có khả năng thực hiện việc chuyển đổi từ kiểu lambda trên dòng 'auto r = ...;' thành kiểu trả về 'f', là' int (__cdecl *) (void) ' . Đúng nếu tôi sai, bởi vì tôi hơi bối rối. :) –

+0

@TimothyShields: GCC là sai để chấp nhận mã như C++ 11 (cho C++ 14 CD đó là chính xác mặc dù). Visual Studio là đúng trong không chấp nhận mã nhưng vì lý do sai: nó không nên cố gắng chuyển đổi một lambda stateful đến một con trỏ hàm. –

+0

Bạn có thể đưa ra suy nghĩ của mình về câu hỏi liên quan gần đây của tôi không? Tôi nghĩ rằng những câu trả lời tôi nhận được ở đó có thể không chính xác dựa trên những hiểu biết của bạn. http://stackoverflow.com/questions/16661981/what-is-this-compiler-error-when-using-a-lambda-as-a-template-parameter –

Các vấn đề liên quan