2010-05-30 39 views
53

Tôi đọc trên internet nhiều hướng dẫn giải thích cách sử dụng lambdas với thư viện chuẩn (chẳng hạn như std::find), và tất cả đều rất thú vị, nhưng tôi không thể tìm thấy bất kỳ giải thích nào về cách sử dụng lambda cho riêng mình chức năng.Làm thế nào để khai báo một hàm chấp nhận một lambda?

Ví dụ:

int main() 
{ 
    int test = 5; 
    LambdaTest([&](int a) { test += a; }); 

    return EXIT_SUCCESS; 
} 

Làm thế nào tôi nên tuyên bố LambdaTest? Loại đối số đầu tiên của nó là gì? Và sau đó, làm thế nào tôi có thể gọi hàm ẩn danh đi qua nó - ví dụ - "10" làm đối số của nó?

Trả lời

51

Cho rằng bạn cũng có thể muốn chấp nhận con trỏ hàm và đối tượng hàm ngoài lambdas, có thể bạn sẽ muốn sử dụng mẫu để chấp nhận bất kỳ đối số nào với số operator(). Đây là những gì các hàm std giống như find. Nó sẽ trông như thế này:

template<typename Func> 
void LambdaTest(Func f) { 
    f(10); 
} 

Lưu ý rằng định nghĩa này không sử dụng bất kỳ tính năng C++ 0x nào, vì vậy nó hoàn toàn tương thích ngược. Đó chỉ là lời gọi hàm bằng cách sử dụng các biểu thức lambda, cụ thể là C++ 0x.

+0

Đây là câu trả lời hay nhất. – Puppy

+2

Trong trường hợp lỗi, các thông báo lỗi sẽ khó hiểu. – liori

+13

Nó phụ thuộc cho dù đó là tốt nhất. Điều này sử dụng một mẫu, và cái kia thì không. Điều này có nghĩa là hàm không thể ảo được nữa và không thể được định nghĩa riêng trong tệp cpp. 'std :: function' hoàn toàn có khả năng nhận các kiểu lớp đối tượng hàm, mặc dù hơi chậm khi gọi. Nhưng sự khác biệt đó là không đáng kể đối với hầu hết các ứng dụng :) –

53

Nếu bạn không muốn template tất cả mọi thứ, bạn có thể làm như sau:

void LambdaTest (const std::function <void (int)>& f) 
{ 
    ... 
} 
+1

Cú pháp này thực sự cho phép tôi lưu biến chức năng để gọi nó sau, phải không? Ví dụ tôi muốn thực hiện một hàm cho phép thực hiện các truy vấn cơ sở dữ liệu không đồng bộ, trong đó lambda hoạt động như một cuộc gọi lại. (Tất nhiên tôi sẽ không thể truy cập các bao đóng bằng cách tham khảo) –

+1

Không phải là thành ngữ hơn để truyền các hàm theo giá trị? – fredoverflow

+1

@Andreas Bonini: Có, nếu bạn lưu vào 'std :: function' (không phải là tham chiếu), bạn tạo một bản sao của' f'. Tuy nhiên, tôi không chắc chắn lambda/closures xử lý các tham chiếu như thế nào khi đối tượng được nhắc đến ngoài phạm vi, có lẽ UB. @FredOverflow: sự hiểu biết của tôi là 'std :: function' không phải là một đối tượng tầm thường, đặc biệt là khi gói lambdas. Nó có lẽ là tốt hơn để tham khảo nó để tránh sao chép không cần thiết. – doublep

4

Tôi muốn đóng góp ví dụ đơn giản nhưng tự giải thích này. Nó cho thấy làm thế nào để vượt qua "những điều có thể gọi được" (chức năng, đối tượng chức năng, và lambdas) cho một chức năng hoặc một đối tượng.

// g++ -std=c++11 thisFile.cpp 

#include <iostream> 
#include <thread> 

using namespace std; 

// ----------------------------------------------------------------- 
class Box { 
public: 
    function<void(string)> theFunction; 
    bool funValid; 

    Box() : funValid (false) { } 

    void setFun (function<void(string)> f) { 
    theFunction = f; 
    funValid = true; 
    } 

    void callIt() { 
    if (! funValid) return; 
    theFunction (" hello from Box "); 
    } 
}; // class 

// ----------------------------------------------------------------- 
class FunClass { 
public: 
    string msg; 
    FunClass (string m) : msg (m) { } 
    void operator() (string s) { 
    cout << msg << s << endl; 
    } 
}; 

// ----------------------------------------------------------------- 
void f (string s) { 
    cout << s << endl; 
} //() 

// ----------------------------------------------------------------- 
void call_it (void (*pf) (string)) { 
    pf("call_it: hello"); 
} //() 

// ----------------------------------------------------------------- 
void call_it1 (function<void(string)> pf) { 
    pf("call_it1: hello"); 
} //() 

// ----------------------------------------------------------------- 
int main() { 

    int a = 1234; 

    FunClass fc (" christmas "); 

    f("hello"); 

    call_it (f); 

    call_it1 (f); 

    // conversion ERROR: call_it ([&] (string s) -> void { cout << s << a << endl; }); 

    call_it1 ([&] (string s) -> void { cout << s << a << endl; }); 

    Box ca; 

    ca.callIt(); 

    ca.setFun (f); 

    ca.callIt(); 

    ca.setFun ([&] (string s) -> void { cout << s << a << endl; }); 

    ca.callIt(); 

    ca.setFun (fc); 

    ca.callIt(); 

} //() 
+2

Bạn không cần funValid: http://en.cppreference.com/w/cpp/utility/functional/function/operator_bool, chỉ cần nói 'if (! theFunction)' –

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