2016-12-13 14 views
6

Tôi đang cố gắng viết hàm lambda C++ và không muốn sử dụng auto làm loại. Hiện nay nó trông giống như:Loại hàm lambda, sử dụng tự động

#include <iostream> 

int main() { 
// Sends the address of an integer to a function which prints out the contents; 
    auto print_int = [](int* a) {std::cout << *a << std::endl;}; 
    int a; 
    a = 3; 
    print_int(&a); 
    return 0; 
} 

Tuy nhiên, tôi muốn thay đổi auto một cái gì đó giống như std::function<void(int)> nhưng không chắc chắn như thế nào. Câu trả lời cho

dường như có liên quan, nhưng tôi không chắc chắn làm thế nào để thích nghi với nó. Cảm ơn.

+1

Bạn đã thử 'std :: function = [] (int * a) {std :: cout << * a << std :: endl;};'? – NathanOliver

+2

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

+4

Chính xác thì 'tự động' là vấn đề gì? – Yakk

Trả lời

5

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.

+0

Nếu các khái niệm được chấp nhận, bạn có thể làm chính xác những gì OP muốn với 'Callable print_int = [] (int * a) {...}; 'Cho đến lúc đó,' auto' chỉ là phiên bản dễ chấp nhận hơn. – Oktalist

1

Lambda có kiểu ẩn danh riêng của nó.

Bạn có thể chuyển đổi lambda của bạn thành std::function<void(int*)>
(hoặc cho lambda vô hình đến void (*)(int*)).

Bạn có thể tạo functor của bạn một cách rõ ràng, do đó bạn cung cấp cho nó một cái tên, một cái gì đó như:

class Print_int 
{ 
public: 
    void operator()(int* a) const {std::cout << *a << std::endl;} 
}; 

và sau đó

Print_int print_int; 
+0

Tìm cách tránh tạo các lớp học. – oliversm

2

Ở đây bạn đi:

int a; 
[](int* a) {std::cout << *a << std::endl;}(&a); 

Không auto sử dụng.


Tuy nhiên, tôi muốn thay đổi tự động để một cái gì đó giống như std::function<void(int)> nhưng không chắc chắn như thế nào.

Điều đó chắc chắn có thể xảy ra. std::functional có một hàm tạo chuyển đổi khuôn mẫu. Bạn chỉ cần truyền lambda cho constructor và đó là tất cả để có nó. Ngoài ra, bạn cần phải sửa loại đối số vì lambda của bạn mong đợi một số int*, không phải là int (đây là loại lỗi tự động auto sửa lỗi tự động).

std::function<void(int*)> print_int = [](int* a) {std::cout << *a << std::endl;}; 

Lưu ý rằng có hai hạn chế đối với điều này.

  • std::function trình bao bọc là lớp gián tiếp che giấu loại thực tế của đối tượng có thể gọi. Lớp trình bao bọc này cho biết thêm chi phí thời gian chạy và ngăn một số tối ưu hóa.
  • Bạn phải cập nhật thủ công loại nếu bạn thực hiện thay đổi đối với giá trị trả lại hoặc đối số của lambda.
Các vấn đề liên quan