Lambdas có nghĩa là để được sử dụng với một trong hai auto
hoặc như mẫu tham số. Bạn không bao giờ biết loại lambda và bạn không thể gõ nó. Mỗi lambda có loại riêng của nó. Ngay cả khi bạn biết tên của loại, tên loại của họ thường chứa ký tự bị cấm trong tên loại.
Tại sao lambda có loại của riêng mình? bởi vì trong thực tế, trình biên dịch tạo ra một lớp được xác định một chút như thế:
struct /* unnamed */ {
// function body
auto operator()(int* a) const {
std::cout << *a << std::endl;
}
} print_int; // <- instance name
Mã này rất gần tương đương (tôi bỏ qua toán tử chuyển đổi). Như bạn có thể thấy, bạn đã sử dụng tự động, vì lambdas đang suy ra kiểu trả về.
Một số sẽ nói sử dụng std::function<void(int*)>
, nhưng tôi không đồng ý. std::function
là một wrapper đa hình xung quanh bất cứ điều gì có thể gọi. Vì lambdas là các loại có thể gọi được, chúng phù hợp với nó. Tôi nói cách khác, nó hoạt động giống như std::any
nhưng với một nhà điều hành cuộc gọi. Nó sẽ gây ra chi phí trong ứng dụng của bạn.
Vì vậy, bạn nên làm gì?
sử dụng auto
! auto
không phải là xấu. Trong thực tế, nó thậm chí có thể làm cho mã của bạn nhanh hơn và giảm việc nhập không cần thiết. Nếu bạn cảm thấy không thoải mái với auto
, bạn cũng không nên! auto
là rất tốt, đặc biệt là nếu bạn không có sự lựa chọn;)
Trong thực tế, bạn có thể tránh sử dụng auto
bằng cách sử dụng một mẫu tham số:
template<typename F, typename Arg>
void parametric_print(F function, Arg&& arg) {
function(std::forward<Arg>(arg));
}
Sau đó sử dụng nó như thế này:
int main() {
int a = 3;
parametric_print([](int* a) {std::cout << *a << std::endl;}, &a);
}
Có bạn đi, không auto
!Tuy nhiên, tham số mẫu được suy luận với cùng một quy tắc như auto
. Trong thực tế, nếu khái niệm được chấp nhận vào tiêu chuẩn, bạn có thể viết các chức năng tương tự mẫu như thế này:
// maybe C++20
void parametric_print(auto function, auto&& arg) {
function(std::forward<decltype(arg)>(arg));
}
Như mentionned bởi Oktalist, nếu khái niệm này được chấp nhận vào tiêu chuẩn, sau đó bạn có thể thay thế auto
với Callable
:
Callable print_int = [](int* a) { std::cout << *a << std::endl; };
Nhưng nó không dẫn đến một loại khác, nó chỉ thực thi một số quy tắc khi loại bỏ loại.
Bạn đã thử 'std :: function = [] (int * a) {std :: cout << * a << std :: endl;};'? –
NathanOliver
Tên loại bê tông của hàm lambda không được chỉ định theo tiêu chuẩn. Bạn cũng không nên quan tâm đến nó khi một lambda thực sự được gọi. – StoryTeller
Chính xác thì 'tự động' là vấn đề gì? – Yakk