2014-11-09 17 views
16

Như tôi biết tất cả các kiểu dữ liệu phải được biết tại thời gian biên dịch, và lambda không phải là một kiểu. Lambda có được dịch sang số anonymous struct with operator() hoặc std::function không?Loại lambdas nào được biên dịch thành?

Ví dụ,

std::for_each(v.begin(), v.end(), [](int n&){n++;}); 
+2

'std :: function' không có kết nối ngôn ngữ như' std :: initializer_list'. – chris

+0

Nó xuất phát từ sự thiếu hiểu biết của tôi. Hoàn toàn ngẫu nhiên. – texasbruce

+2

Loại Lambda là [không xác định] (http://stackoverflow.com/questions/7951377/what-is-the-type-of-lambda-when-deduced-with-auto-in-c11). – Marcin

Trả lời

14

Một biến thể của as-if rule, tiêu chuẩn C++ 11 nói :

§5.1.2/3 [..] An thực hiện có thể xác định loại đóng khác với những gì được mô tả dưới đây cung cấp này không làm thay đổi hành vi quan sát được của chương trình khác hơn bằng cách thay đổi:

- kích thước và/hoặc sự liên kết của các loại đóng cửa,

- cho dù kiểu đóng cửa là trivially copyable (khoản 9),

- cho dù kiểu đóng cửa là một lớp học tiêu chuẩn bố trí (khoản 9), hoặc

- cho dù kiểu đóng cửa là một lớp POD (Khoản 9).

Tôi tin rằng đây là ý nghĩa của mọi người khi họ nói rằng đó là unspecified. Tuy nhiên những gì đang được bảo đảm như đã nêu trong câu trả lời khác được như sau:

tác giả gốc: Lightness Races in Orbit

[C++11: 5.1.2/3]:Các loại lambda-biểu (mà cũng là kiểu của đối tượng đóng cửa) là loại không công khai duy nhất chưa được đặt tên - được gọi là loại đóng cửa - có thuộc tính là d được ghi dưới đây. Loại lớp này không phải là tổng hợp (8.5.1). Loại đóng cửa được khai báo trong phạm vi khối nhỏ nhất, phạm vi lớp học, hoặc phạm vi không gian tên chứa tương ứng lambda-biểu. [..]

Mệnh tiếp tục danh sách các thuộc tính của loại hình này khác nhau. Dưới đây là một số điểm nổi bật :

[C++11: 5.1.2/5]: Kiểu đóng cửa cho một lambda-biểu có một công inline hàm operator gọi (13.5.4) có các tham số và kiểu trả về được mô tả bởi các lambda-biểu 's tham số-khai-khoảndấu-trở-type tương ứng. [..]

[C++11: 5.1.2/6]: Kiểu đóng cửa cho một lambda-biểu không có lambda-chụp có một tổ chức phi ảo không rõ ràng const chức năng chuyển đổi nào để con trỏ hoạt động có thông số tương tự và trả về các kiểu như toán tử gọi hàm của kiểu đóng. Giá trị trả về bởi chức năng chuyển đổi này sẽ là địa chỉ của một hàm đó, khi gọi, có tác dụng tương tự như cách gọi hàm operator gọi loại đóng của.

6

Một biểu thức lambda xây dựng một loại vô danh, với mỗi người có một kiểu khác nhau. Chúng không phải là triển khai std::function. Xem thêm thông tin được cung cấp ở đây: What is a lambda expression in C++11? và ở đây: How to convert a lambda to an std::function using templates

Bạn có thể tiết lộ các loại trên trình biên dịch cụ thể của bạn với một thủ thuật như thế này:

void foo(int); 

int main() { 
    auto a = []{ return 1; }; 
    auto b = []{ return 1; }; 

    foo(a); 

    foo(b); 

    return 0; 
} 

Biên soạn với kêu vang trên mac của tôi mang lại:

/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:11:5: error: no matching function for call to 'foo' 
    foo(a); 
    ^~~ 
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from 
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:8:14>' to 'int' for 1st argument 
void foo(int); 
    ^
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:13:5: error: no matching function for call to 'foo' 
    foo(b); 
    ^~~ 
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from 
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:9:14>' to 'int' for 1st argument 
void foo(int); 

@Barry chỉ ra rằng bạn có thể sử dụng typeid để thay thế. Nếu tôi in ra typeid(a).name()typeid(b).name() trên hệ thống của tôi, tôi nhận được:

Z4mainE3$_0 
Z4mainE3$_1 

mà demangle để

main::$_0 
main::$_1 

Chỉ muốn bao gồm này cho đầy đủ. Tôi thực sự tìm thấy phiên bản thông báo lỗi một chút thông tin hơn. :)

+0

Vì vậy, nó là cấu trúc ẩn danh? – texasbruce

+0

Theo quy trình xây dựng của @ texasbruce, chúng có một loại, nhưng nó là một chi tiết thực hiện. – sfjac

+1

@sfjac Nếu bạn thực sự muốn xem loại, bạn chỉ có thể sử dụng 'typeid()' và chuyển nó qua [demangler] (http://stackoverflow.com/questions/281818/unmangling-the-result-of -stdtype-infoname) – Barry

12

Từ §5.1.2.3 tiêu chuẩn:

Các loại lambda-biểu ... là một độc đáo, chưa đặt tên phi công đoàn kiểu lớp

Đó là loại riêng của nó. Mỗi lần. Ví dụ:

auto a = []{ return 1; }; 
auto b = []{ return 1; }; 

ab nhất thiết phải có các loại khác nhau. Cả hai đều chuyển đổi thành std::function<int()>, nhưng không phải với nhau:

std::function<int()> c = a; // OK 
a = b; // NOPE 

Thêm một vài ví dụ khác để thêm một số rõ ràng:

decltype(a) a2 = a; // OK, explicitly specifying the correct type 

template <typename F> 
void foo(F f) { ... } 

foo(a); // calls foo<decltype(a)>, not foo<std::function<int()> 
+0

Điều này không trả lời được câu hỏi của tôi. Tôi biết lambda không có một loại (như tôi đã nêu trong câu hỏi). Câu hỏi của tôi là cách chúng được biên soạn vì chúng không có loại. – texasbruce

+5

@texasbruce Bạn hiểu lầm. Họ * làm * có một loại. Nó chỉ là * duy nhất * và * không có tên *. Trong ví dụ của tôi, bạn có thể làm 'using T = decltype (a); T a2 = a; 'Điều đó sẽ biên dịch tốt. – Barry

+0

@texasbruce: Câu trả lời cho biết loại biểu thức lambda là một loại lớp không phải là công đoàn không có tên. Đó là một tuyên bố khác với "không có loại". Một lambda * có * có kiểu, nhưng kiểu không có tên. – rici

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