Typically I use the following pattern when accepting a lambda as an argument to a function (A template class passed-by-value):
template
A copy is a copy, so you cannot mutate the original, might have some performance impact when a lot of data is involved:
#include
using namespace std;
template
void call_value(Fn f) { f(); }
template
void call_ref(Fn & f) { f(); }
template
void call_cref(Fn const & f) { f(); }
struct Data {
Data() {}
Data(Data const &) {
cout << "copy" << endl;
}
Data(Data &&) {
cout << "move" << endl;
}
};
int main(int, char **) {
Data data;
auto capref = [&data] () {};
cout << "capture by value, so we get a ";
auto capcp = [data] () {};
cout << " the lambda with a reference ... ";
call_value(capref);
cout << " could now be called and mutate .. ";
call_ref(capref);
call_cref(capref);
cout << " but won't, as it had to be declared mutable " << endl;
cout << "the lambda with an instance: ";
call_value(capcp);
cout << "but not ";
call_ref(capcp);
call_cref(capcp);
cout << " the reference versions " << endl;
bool en = false;
auto trigger = [en](bool enable = true) mutable {
if (en) {
cout << "fire!" << endl;
}
if (en or enable) {
en = true;
}
};
cout << "won't shoot" << endl;
trigger(false);
call_value(trigger);
trigger(false);
call_ref(trigger);
cout << "and now ... ";
trigger(false);
// const ref won't work
return 0;
}
See it in action.
Don't forget: lambdas are mere syntactic sugar for callable classes. (But extremely helpful)