2011-01-13 51 views
31

Tôi tự hỏi chúng ta nên sử dụng biểu thức lambda trên functor trong C++. Đối với tôi, hai kỹ thuật này về cơ bản giống nhau, ngay cả hàm functor thanh lịch và sạch hơn lambda. Ví dụ, nếu tôi muốn tái sử dụng vị từ của tôi, tôi phải sao chép phần lambda hơn và hơn. Vì vậy, khi nào lambda thực sự đi vào vị trí?Biểu thức Lambda so với Functor trong C++

+1

BTW, không biết rằng tôi muốn đặt "lambda" làm mã. Nó không phải là một từ khóa hoặc loại trong C + +. Có một thứ như "biểu thức lambda" nhưng "lambda" không phải là thứ bạn thấy trong mã trừ khi bạn đang sử dụng thư viện lambda của boost hoặc thực sự có cái gì đó được gọi là trong mã của riêng bạn. –

+0

@Noah Roberts: cảm ơn vì đã chỉ ra điều đó. Đã chỉnh sửa! Quan điểm của tôi là nhấn mạnh từ đó. – Chan

Trả lời

12

1) Nó tầm thường và cố gắng chia sẻ nó là công việc nhiều hơn lợi ích.

2) Xác định hàm functor chỉ đơn giản là thêm độ phức tạp (do phải tạo một loạt các biến thành viên và crap).

Nếu không có điều nào trong số đó là đúng thì có lẽ bạn nên suy nghĩ về việc xác định một hàm.

Chỉnh sửa: có vẻ như bạn cần một ví dụ về thời điểm tốt nhất nên sử dụng lambda trên một hàm. Ở đây bạn đi:

typedef std::vector< std::pair<int,std::string> > whatsit_t; 

int find_it(std::string value, whatsit_t const& stuff) 
{ 
    auto fit = std::find_if(stuff.begin(), stuff.end(), [value](whatsit_t::value_type const& vt) -> bool { return vt.second == value; }); 

    if (fit == stuff.end()) throw std::wtf_error(); 

    return fit->first; 
} 

Without lambdas bạn sẽ phải sử dụng một cái gì đó tương tự như xây dựng một functor ngay tại chỗ hoặc viết một đối tượng functor bên ngoài có thể kết nối với một cái gì đó khó chịu tầm thường.

BTW, tôi nghĩ có thể wtf_error là tiện ích.

+0

Đừng quên rằng bạn làm lộn xộn không gian tên của bạn với các lớp functor. –

+2

@Paul Nathan: Điều đó đã được giải quyết bằng các không gian tên ẩn danh. –

+0

Roberts: cảm ơn một ví dụ rất hay về việc sử dụng Lamda. – Chan

0

Như bạn đã chỉ ra, nó hoạt động tốt nhất khi bạn cần một lần duy nhất và chi phí mã hóa để viết nó ra như một hàm không đáng giá.

+0

cảm ơn bạn đã trả lời nhanh chóng. Nhưng tôi không hiểu động lực để phát minh ra 'lamda' là gì, vì tôi nghĩ khó đọc và hơn nữa nó không thể tái sử dụng được. Nó cũng không có tên, vì vậy mã đọc đòi hỏi nhiều thời gian hơn. – Chan

+0

@Chan: Herb Sutter là một trong những người ủng hộ giọng hát nhiều nhất cho lambdas. Ông đã đăng một số cuộc đàm phán về họ: http://herbsutter.com/2010/10/30/pdc-languages-panel-andshortened-lambdas-talk/. Đã không xem chúng bản thân mình, nhưng họ sẽ không có nghi ngờ cho bạn biết những gì * ông * nghĩ rằng họ đang tốt cho, và đưa ra một số ví dụ về khi ông sẽ sử dụng chúng. –

+0

@Steve Jessop: cảm ơn vì liên kết. Tôi sẽ xem nó. – Chan

14

Biểu thức lambda tạo một hàm functor không tên, đó là đường cú pháp.

Vì vậy, bạn chủ yếu sử dụng nó nếu nó làm cho mã của bạn trông đẹp hơn. Điều đó thường sẽ xảy ra nếu một trong hai (a) bạn sẽ không sử dụng lại hàm functor, hoặc (b) bạn sẽ sử dụng lại nó, nhưng từ mã hoàn toàn không liên quan đến mã hiện tại để chia sẻ nó, về cơ bản cuối cùng tạo ra my_favourite_two_line_functors.h và có các tệp khác nhau phụ thuộc vào nó.

Khá nhiều điều kiện tương tự mà bạn sẽ nhập bất kỳ dòng mã nào và không trừu tượng hóa khối mã đó thành một hàm. Điều đó nói rằng, với các báo cáo phạm vi cho C++ 0x, có một số nơi mà bạn đã sử dụng một hàm functor trước khi nó có thể làm cho mã của bạn trông đẹp hơn bây giờ để viết mã như một vòng lặp, chứ không phải một functor hoặc một lambda.

8

Các chức năng nhỏ không được lặp lại.

Lời phàn nàn chính về các functors là chúng không ở cùng nơi mà chúng được sử dụng. Vì vậy, bạn phải tìm và đọc các functor ra khỏi bối cảnh đến nơi nó đã được sử dụng trong (ngay cả khi nó chỉ được sử dụng ở một nơi).

Vấn đề khác là functor yêu cầu một số hệ thống dây điện để lấy thông số vào đối tượng functor. Không phức tạp nhưng tất cả các mã soạn sẵn cơ bản. Và tấm nồi hơi là dễ bị cắt và dán vấn đề.

Lambda hãy thử và sửa cả hai. Nhưng tôi sẽ sử dụng functors nếu chức năng được lặp đi lặp lại ở nhiều nơi hoặc lớn hơn (không thể nghĩ ra một thuật ngữ thích hợp vì nó sẽ được bối cảnh nhạy cảm) nhỏ.

10

Lambdas là về cơ bản chỉ là cú pháp đường thực hiện functors (NB: đóng cửa không đơn giản.Trong C++ 0x, bạn có thể sử dụng từ khóa tự động để lưu trữ lambdas cục bộ, và std :: function sẽ cho phép bạn lưu trữ lambdas, hoặc truyền chúng xung quanh một cách an toàn kiểu.

Kiểm tra các Wikipedia article on C++0x.

0

Về mặt lý thuyết, quyết định trong đó để sử dụng được thúc đẩy bởi cùng một tiêu chí như sử dụng một biến có tên so với một biểu hiện tại chỗ hoặc liên tục ...

size_t length = strlen(x) + sizeof(y) + z++ + strlen('\0'); 
... 
allocate(length); 
std::cout << length; 

. ..tại đây, việc tạo một biến chiều dài khuyến khích chương trình xem xét tính chính xác và ý nghĩa của nó trong việc tách biệt nó sau này. Tên hy vọng truyền tải đủ để nó có thể được hiểu trực giác và độc lập với giá trị ban đầu của nó. Sau đó nó cho phép giá trị được sử dụng nhiều lần mà không lặp lại biểu thức (trong khi xử lý z là khác nhau). Trong khi ở đây ...

allocate(strlen(x) + sizeof(y) + z++ + strlen('\0')); 

... mã tổng được giảm và giá trị được bản địa hóa tại điểm cần thiết. Điều duy nhất để "chuyển tiếp" từ việc đọc dòng này là các tác dụng phụ của phân bổ và tăng (z), nhưng không có biến cục bộ bổ sung nào có phạm vi hoặc sử dụng sau này để xem xét. Các lập trình viên phải tinh thần sắp xếp trạng thái ít hơn trong khi tiếp tục phân tích mã của họ.

Sự phân biệt giống nhau áp dụng cho các hàm so với câu lệnh nội tuyến. Với mục đích trả lời câu hỏi của bạn, các functors so với lambdas có thể được xem như một trường hợp cụ thể của hàm này so với quyết định nội tuyến.

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