How can I store a lambda expression as a field of a class in C++11?
C++ClassLambdaC++11FieldC++ Problem Overview
I'd like to create a class where the client can store a lambda expression like []() -> void {}
as a field of the class, but I can't figure out how to do so. One answer suggested using decltype
, which I tried with no success. Here is a ideone source link. The below is the source and result:
#include <cstdio>
auto voidLambda = []()->void{};
class MyClass {
public:
decltype(voidLambda) t;
MyClass(decltype(voidLambda) t) {
this->t = t;
}
};
int main() {
MyClass([] {
printf("hi");
});
}
Result:
prog.cpp: In constructor 'MyClass::MyClass(<lambda()>)':
prog.cpp:3:79: error: no matching function for call to '<lambda()>::__lambda0()'
prog.cpp:2:20: note: candidates are: <lambda()>::<lambda>(const<lambda()>&)
prog.cpp:2:20: note: <lambda()>::<lambda>(<lambda()>&&)
prog.cpp:3:88: error: no match for 'operator=' in '((MyClass*)this)->MyClass::t = t'
prog.cpp: In function 'int main()':
prog.cpp:5:27: error: no matching function for call to 'MyClass::MyClass(main()::<lambda()>)'
prog.cpp:3:48: note: candidates are: MyClass::MyClass(<lambda()>)
prog.cpp:3:14: note: MyClass::MyClass(const MyClass&)
Does anyone know how to do this?
C++ Solutions
Solution 1 - C++
If you want a class member to be a lambda expression, consider using the std::function<>
wrapper type (from the <functional>
header), which can hold any callable function. For example:
std::function<int()> myFunction = [] { return 0; }
myFunction(); // Returns 0;
This way, you don't need to know the type of the lambda expression. You can just store a std::function<>
of the appropriate function type, and the template system will handle all the types for you. More generally, any callable entity of the appropriate signature can be assigned to a std::function<>
, even if the the actual type of that functor is anonymous (in the case of lambdas) or really complicated.
The type inside of the std::function
template should be the function type corresponding to the function you'd like to store. So, for example, to store a function that takes in two int
s and returns void, you'd make a std::function<void (int, int)>
. For a function that takes no parameters and returns an int
, you'd use std::function<int()>
. In your case, since you want a function that takes no parameters and returns void
, you'd want something like this:
class MyClass {
public:
std::function<void()> function;
MyClass(std::function<void()> f) : function(f) {
// Handled in initializer list
}
};
int main() {
MyClass([] {
printf("hi")
}) mc; // Should be just fine.
}
Hope this helps!
Solution 2 - C++
The only way I can think of to store a lambda in a class is to use a template with a helper make_
function:
#include <cstdio>
#include <utility>
template<class Lambda>
class MyClass {
Lambda _t;
public:
MyClass(Lambda &&t) : _t(std::forward<Lambda>(t)) {
_t();
}
};
template<class Lambda>
MyClass<Lambda> make_myclass(Lambda &&t) {
return { std::forward<Lambda>(t) };
}
int main() {
make_myclass([] {
printf("hi");
});
}
Solution 3 - C++
In case of []
(empty capture) simple function pointer can be used. Declaration syntax is ReturnType (*pointer_name) (Arg1T, Arg2T);
for pointer, ReturnType (&ref_name) (/*void*/);
for reference (can't be null). Lambda with empty capture block is implicitly convertible to function pointer with same signature. And std::function
have runtime and size (it is at least three times larger) overhead.
struct S
{
void (*f_p)() {}; // `{}` means `= nullptr`;
};
int main()
{
S s { [] { std::cout << "Lambda called\n"; }};
s.f_p();
S s2;
if (s2.f_p) // check for null
s.f_p();
s2.f_p = [] { std::cout << "Lambda2 called\n"; };
s2.f_p();
s2.f_p = std::terminate; // you can use regular functions too
s2.f_p();
}
Output
Lambda called
Lambda2 called
terminate called without an active exception