Làm thế nào để lambda chung hoạt động trong C ++ 14?


114

Lambda chung chung hoạt động autonhư thế nào ( từ khóa làm kiểu đối số) trong tiêu chuẩn C ++ 14?

Nó dựa trên các mẫu C ++ mà đối với mỗi loại đối số khác nhau, trình biên dịch tạo ra một hàm mới với cùng một nội dung nhưng các kiểu được thay thế (đa hình thời gian biên dịch) hay nó giống với các kiểu chung của Java hơn (kiểu xóa)?

Ví dụ về mã:

auto glambda = [](auto a) { return a; };

6
Cố định C ++ 14, ban đầu được sử dụng C ++ 11 trong câu hỏi
sasha.sochka

Câu trả lời:


130

Lambdas chung đã được giới thiệu trong C++14.

Đơn giản, kiểu bao đóng được xác định bởi biểu thức lambda sẽ có toán tử cuộc gọi được tạo mẫu hơn là toán tử cuộc gọi thông thường, không phải mẫu C++11của lambdas (tất nhiên, khi autoxuất hiện ít nhất một lần trong danh sách tham số).

Vì vậy, ví dụ của bạn:

auto glambda = [] (auto a) { return a; };

Sẽ tạo glambdamột phiên bản của loại này:

class /* unnamed */
{
public:
    template<typename T>
    T operator () (T a) const { return a; }
};

Đoạn 5.1.2 / 5 của Dự thảo Tiêu chuẩn C ++ 14 n3690 chỉ định cách toán tử cuộc gọi của kiểu đóng của một biểu thức lambda nhất định được xác định:

Kiểu đóng cho biểu thức lambda không chung chung có toán tử gọi hàm nội tuyến công khai (13.5.4) có các tham số và kiểu trả về được mô tả bởi tham số-khai báo-mệnh đề và kiểu dấu-trả lại của biểu thức lambda tương ứng. Đối với lambda chung, kiểu đóng có mẫu thành viên toán tử lệnh gọi hàm nội tuyến công khai (14.5.2) có mẫu-tham số-danh sách bao gồm một tham số kiểu mẫu được phát minh cho mỗi lần xuất hiện tự động trong mệnh đề tham số-khai báo của lambda, theo trình tự xuất hiện. Tham số mẫu kiểu được phát minh là một gói tham số nếu khai báo tham số tương ứng khai báo một gói tham số hàm (8.3.5). Kiểu trả về và các tham số hàm của mẫu toán tử cuộc gọi hàm được bắt nguồn từ kiểu dấu-trả lại và khai báo tham số của lambda-expression bằng cách thay thế mỗi lần xuất hiện của auto trong phần khai báo của mệnh đề tham số-khai báo bằng tên của thông số-mẫu được phát minh tương ứng.

Cuối cùng:

Nó có tương tự như các mẫu trong đó đối với mỗi trình biên dịch kiểu đối số khác nhau sẽ tạo ra các hàm có cùng nội dung nhưng đã thay đổi kiểu không hay nó giống với các hàm chung của Java hơn?

Như đoạn trên giải thích, lambdas chung chung chỉ là đường cú pháp cho các hàm duy nhất, không có tên với một toán tử cuộc gọi được tạo mẫu. Điều đó sẽ trả lời câu hỏi của bạn :)


7
Tuy nhiên, chúng cũng cho phép một lớp được xác định cục bộ với một phương thức khuôn mẫu. Cái nào mới.
Yakk - Adam Nevraumont

2
@Yakk: Không phải hạn chế đối với các mẫu hàm cục bộ đã bị loại bỏ hoàn toàn với C ++ 11 rồi phải không?
Sebastian Mach

2
@phresnel: Nope, hạn chế mà chưa được dỡ bỏ
Andy Prowl

1
@AndyProwl: Tôi nhận ra sai lầm của mình. Gì đã được dỡ bỏ thực sự được sử dụng các loại địa phương như các đối số mẫu (như trong int main () { struct X {}; std::vector<X> x; })
Sebastian Mach

1
@phresnel: Đúng vậy, điều đó đã thực sự thay đổi
Andy Prowl

25

Thật không may , chúng không phải là một phần của C ++ 11 ( http://ideone.com/NsqYuq ):

auto glambda = [](auto a) { return a; };

int main() {}

Với g ++ 4.7:

prog.cpp:1:24: error: parameter declared auto
...

Tuy nhiên , cách nó có thể được triển khai trong C ++ 14 theo đề xuất của Portland cho lambdas chung :

[](const& x, & y){ return x + y; }

Điều này sẽ dẫn đến phần lớn việc tạo ra một lớp trình hàm ẩn danh thông thường, nhưng với việc thiếu các loại, trình biên dịch sẽ phát ra một thành viên mẫu- operator():

struct anonymous
{
    template <typename T, typename U>
    auto operator()(T const& x, U& y) const -> decltype(x+y)
    { return x + y; }
};

Hoặc theo đề xuất mới hơn Đề xuất cho Biểu thức Lambda Chung (Đa hình)

auto L = [](const auto& x, auto& y){ return x + y; };

--->

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;

Vì vậy, có, đối với mỗi hoán vị của các tham số, một khởi tạo mới sẽ phát sinh, tuy nhiên, các thành viên của trình hàm đó sẽ vẫn được chia sẻ (tức là các đối số được bắt).


6
Đề xuất cho phép loại bỏ type-specifier là hoàn toàn kỳ cục.
Lightness Races ở Orbit

Họ đã đi vào với g ++ - 4,9 . Bạn cần cung cấp -std=c++1y.
emsr

Tôi không nhận ra Ideone chưa có gcc-4.9 và C ++ 14.
emsr

câu hỏi: điều này autocó các quy tắc khấu trừ giống như tự động cổ điển? Nếu chúng ta đề cập đến phép loại suy theo mẫu, điều đó có nghĩa là tự động không phải là tự động, nó giống các quy tắc như suy luận kiểu mẫu. Sau đó, câu hỏi đặt ra là: sự suy diễn khuôn mẫu có tương đương với auto?
v.oddou

@ v.oddou: "Tự động cổ điển" là tốt. Đối với tôi, "tự động cổ điển" có nghĩa là "Biến ngăn xếp", và đã từng được sử dụng trái ngược với statichoặc register:) Dù sao, có, sử dụng autoở đó có nghĩa là dưới mui xe, một mẫu bình thường được tạo. Trên thực tế, lambda sẽ được thay thế bên trong trình biên dịch bởi một lớp functor và một autotham số có nghĩa là template <T> ... (T ...)sẽ được phát ra.
Sebastian Mach

17

Đó là một tính năng C ++ 14 được đề xuất (không phải trong C ++ 11) tương tự (hoặc thậm chí tương đương) với các mẫu. Ví dụ, N3559 cung cấp ví dụ này:

Ví dụ: câu lệnh chứa biểu thức lambda chung này:

auto L = [](const auto& x, auto& y){ return x + y; };

có thể dẫn đến việc tạo ra một loại bao đóng và đối tượng hoạt động tương tự như cấu trúc bên dưới:

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.