2010-05-30 3 views
53

Я читал в Интернете много учебников, в которых объяснялось, как использовать лямбды со стандартной библиотекой (например, std::find), и все они были очень интересными, но я не мог найти ни одного объяснения, как я могу использовать лямбда для своих собственных функции.Как объявить функцию, которая принимает лямбда?

Например:

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

    return EXIT_SUCCESS; 
} 

Как я должен объявить LambdaTest? Каков тип его первого аргумента? И затем, как я могу назвать анонимную функцию, передаваемую ей, например, - «10» в качестве аргумента?

ответ

51

Учитывая, что вы, вероятно, также хотите принять функции указателей и объектов функций в дополнение к lambdas, вы, вероятно, захотите использовать шаблоны для принятия любых аргументов с помощью operator(). Это то, что делают std-функции, такие как find. Это будет выглядеть следующим образом:

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

Обратите внимание, что это определение не использует C++ 0x особенности, так что полностью обратно совместимым. Это вызов только функции, использующей лямбда-выражения, которые являются C++ 0x-specific.

+0

Это лучший ответ. – Puppy

+2

В случае ошибок сообщения об ошибках будут трудно понять. – liori

+13

Это зависит от того, лучше ли это. Это использует шаблон, а другой - нет. Это означает, что функция больше не может быть виртуальной и не может быть определена отдельно в файле cpp. 'std :: function' вполне может также использовать типы классов объектов объектов, хотя при вызове он немного медленнее. Но эта разница ничтожна для самых приложений :) –

53

Если вы не хотите, чтобы шаблон все, вы можете сделать следующее:

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

Этот синтаксис фактически позволяет мне сохранить функциональную переменную, чтобы называть ее позже, не так ли? Например, я хотел реализовать функцию, позволяющую выполнять асинхронные запросы к базе данных, где лямбда действует как обратный вызов. (Конечно, я не смог бы получить доступ к закрытию по ссылке) –

+1

Не более ли идиоматично передавать функции по стоимости? – fredoverflow

+1

@Andreas Bonini: Да, если вы сохраните файл 'std :: function' (а не ссылку), вы создадите копию' f'. Тем не менее, я не уверен, как lambda/closures обрабатывают ссылки, когда упомянутый объект выходит за пределы области видимости, вероятно, UB. @FredOverflow: Я понимаю, что 'std :: function' не является тривиальным объектом, особенно при обертывании лямбда. Вероятно, лучше ссылаться на него, чтобы избежать ненужного копирования. – doublep

4

Я хотел бы внести свой вклад этого простой, но сам-пояснительный пример. Он показывает, как передать «вызываемые вещи» (функции, объекты функций и lambdas) функции или объекту.

// 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

Вам не нужен funValid: http://en.cppreference.com/w/cpp/utility/functional/function/operator_bool, просто скажите 'if (! theFunction)' –