Lambdas as class members [duplicate] - c++

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?

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 ints 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!

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");
});
}

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

Related

compile error about template deduction on c++

#include <iostream>
template <int N>
class X {
public:
using I = int;
void f(I i) {
std::cout << "i: " << i << std::endl;
}
};
template <int N>
void fppm(void (X<N>::*p)(typename X<N>::I)) {
p(0);
}
int main() {
fppm(&X<33>::f);
return 0;
}
I just don't understand the compile error message of the code.
error: called object type 'void (X<33>::*)(typename X<33>::I)' is not a function or function pointer
p(0);
I think p is a function which returns void and takes int as its argument. But apparently, it's not. Could somebody give me clue?
Since p is a pointer to a nonstatic member function, you need an instance to call it with. Thus, first instantiate an object of X<33> in main:
int main() {
X<33> x;
fppm(x, &X<33>::f); // <-- Signature changed below to accept an instance
Then in your function, change the code to accept an instance of X<N> and call the member function for it:
template <int N>
void fppm(X<N> instance, void (X<N>::*p)(typename X<N>::I)) {
(instance.*p)(0);
}
The syntax may look ugly but the low precedence of the pointer to member operator requires the need for the parentheses.
As denoted in the comments already, p is a pointer to member function, but you call it like a static function (p(0);). You need a concrete object to call p on:
X<N> x;
(x.*p)(0);
// or:
X<N>* xx = new X<N>();
(xx->*p)(0);
delete xx;
Be aware that the .*/->* operators have lower precedence than the function call operator, thus you need the parentheses.
Side note: Above is for better illustration, modern C++ might use auto keyword and smart pointers instead, which could look like this:
auto x = std::make_unique<X<N>>();
(x.get()->*p)(0);

Access violation on std::function assigned to a lambda

I was trying to play around with std::function and std::bind and I stepped in a problem. I would like to build a general structure that allows me to bind a std::function to a member function without knowing a priori the arguments of the member function. I wrote this thing
template<typename Class, typename Return, typename ...Args>
struct Caller
{
private:
std::function<Return(Args ...)> callerFunction;
Caller(const Caller&) = delete;
Caller(Caller&&) = delete;
Caller& operator=(const Caller&) = delete;
public:
~Caller() = default;
Caller() = default;
Caller(Class& instance, Return(Class::*function)(Args...))
{
callerFunction = [&](Args... args) { return (instance.*function)(args...); };
}
Return operator() (Args ... args)
{
return callerFunction(args...);
}
};
FYI I know that the arguments to the function are passed by value (I encountered some problem using universal references with variadic template, I will work on that later).
The problem here is that when I fire the function with operator() I get an Access Violation Error. I tried to narrow down the problem and created a structure without the variadic arguments (allowing the member function to have just an int as argument) and I saw that assigning the lambda to the std::function was given me the same error, but if I used std::bind with a placeholder everything was just fine.
The test ground is this
class A
{
public:
bool foo(int a)
{
std::cout << a << std::endl;
return true;
}
};
int main()
{
A a;
a.foo(9);
Caller<A, bool, int> caller(a, &A::foo);
caller(10);
std::cin.ignore();
}
Using the lambda, do I need to save the instance of the class in order to call properly the member function?
As state in comment, you have dangling pointer of function, you could use instead:
Caller(Class& instance, Return(Class::*function)(Args...))
{
callerFunction = [&instance, function](Args... args) {
return (instance.*function)(std::forward<Args>(args)...);
};
}
Note: instance should also outlives Caller.
Don't use [&] when the object or copies of it outlives the current scope.
You are capturing references to local variables and storing them beyond the current scope.

How to avoid lambda functions with a known function parameter?

In the following code, I have a variable called data. It holds a functions inside itself to call them later. Let's assume data is defined in another library and I cannot change its type. I assign a template function to each member of it where a portion of this function is known (s3) and a portion must be given when it is called (true). I cannot pass something like this:
data[0]=test_func(?,s3); // error
instead, I have to pass a lambda function to it :
data[0]=[](bool b){test_func(b,s3);}; // ok
But the lambda function does not look neat especially when we have an array of 100 of these assignments. It there any way to avoid lambda functions by just changing the test_func in any way? even using lambda inside test_func is ok to me because it is just written once.
#include <iostream>
#include <functional>
template<typename F>
void test_func(bool b,F f)
{
if(b)
f();
}
void s1()
{
std::cout<<"s1 \n";
}
void s2()
{
std::cout<<"s2 \n";
}
void s3()
{
std::cout<<"s3 \n";
}
int main()
{
test_func(true,s1);
test_func(true,s2);
test_func(false,s1);
test_func(true,s2);
/////////////////
std::function<void(bool)> data[100];
// data=test_func(?,s3); // error
data[0]=[](bool b){test_func(b,s3);}; // ok
data[0](true);
return 0;
}
If you want to avoid a lambda function completely as well as templates you can use a functional (class with operator()):
typedef void (&F)(void);
class TestFunc {
F f;
public:
TestFunc(const F f) : f(f) {}
void operator()(bool B) const {
if(B) f();
}
};
Assign it with TestFunc(s3). Just typedef F to the function type, no need for a template:
typedef void (&F)(void);
and remove the template completely - I usually prefer less templates if possible, but that's taste. A template would only really be called for if you need different function signature support.
To use a standard library functional just change the typedef:
typedef std::function<void(void)> F;
If each s_n is a regular function with an identical signature, you can just remove that f parameter from test_func and instead pass the function itself as template parameter.
template<void(&f)()>
void test_func(bool b)
{
if(b)
f();
}
And use like this:
data[0] = test_func<s1>;
Function pointers and references are explicitly allowed as template non-type parameters by [temp.param/4]:
A non-type template-parameter shall have one of the following
(optionally cv-qualified) types:
[...]
pointer to object or pointer to function,
lvalue reference to object or lvalue reference to function,
You could create your lambda in a helper function:
#include <iostream>
#include <string>
#include <functional>
#include <vector>
template<typename F>
void test_func(bool b,F f) {
if(b) {
f();
}
}
std::function<void(bool)> wrap_function(const std::function<void(void)> &f) {
return [f](bool b){test_func(b,f);};
}
void s1() {
std::cout<<"s1 \n";
}
int main() {
std::vector<std::function<void(bool)>> data;
data.push_back(wrap_function(s1));
data[0](true);
}
And you should use std::vector, std::array or another std container instead of std::function<void(bool)> data[100]

Passing a pointer to a member function as argument for a void* function

I have the following function:
void PerformAction(void(*pf_action)());
and the following class:
class A
{
public:
void DoSomething();
}
I want to be able to do this:
int main()
{
A a;
PerformAction(&(a.DoSomething);
return 0;
}
I have seen many answers that say that the function signature should be:
void PerformAction(void(A::*)());
This is not what I want.
I want to able to pass it any function/method that receives no parameters and returns void. Not just member methods of A or just global functions.
Is this possible in C++?
Plain function pointers and member function pointers are different things.
Member functions take a hidden this parameter, whereas plain functions do not. To call a member function through a pointer an object is required to initialize that this parameter.
Hence, you cannot convert a pointer to a non-static member function to a plain function pointer and call through it without passing in an object.
I want to able to pass it any function/method that receives no parameters and returns void. Not just member methods of A or just global functions.
Is this possible in C++?
Yes, it is possible, but you need to use a more flexible type. The way to achieve this is to specify the PerformAction function with a different type. You want to use a type that is callable with zero arguments and returns void, std::function<void ()>. For example change the PerformAction function to be: void PerformAction(std::function<void ()> fn);. This version will allow you to accept anything that's callable with zero arguments and returns void, see the following code for an example.
Example Code
#include <functional>
#include <iostream>
class Foo
{
public:
void bar() { std::cout << "Member function: Foo::bar()\n"; }
};
void bar()
{
std::cout << "Free function: bar()\n";
}
class Functor
{
public:
void operator()() { std::cout << "Functor object\n"; }
};
auto lambda = []() { std::cout << "Lambda expression\n"; };
void doSomething(std::function<void ()> fn)
{
fn();
}
int main()
{
doSomething(bar);
doSomething(Functor());
doSomething(lambda);
Foo foo;
doSomething(std::bind(&Foo::bar, &foo));
return 0;
}
Live Example
Example Output
Free function: bar()
Functor object
Lambda expression
Member function: Foo::bar()

How to pass a lambda in a function with a capture?

My title is my main question.
The code below shows what i want to do, but it causes an error.
class B
{
public:
void DoSomething(void (*func)())
{
func();
}
};
class A
{
public:
int x;
void Start(B* b)
{
auto func = [this]()->void
{
this->x++;
};
b->DoSomething(func);
}
};
If I remove the "this" keyword, then the program works, but then I cant reference the x variable.
So how can I achieve this?
Change
void DoSomething( void (*func)() )
to
void DoSomething( std::function<void()> func )
Your current parameter type void (*func)() is a function pointer, which is a type of callable (something that can be called like a function) that doesn't hold state. That is why your variable this can't be passed into the function.
Only lambdas that capture nothing can be converted to a stateless function pointer.
std::function however can represent (almost) anything callable. It could be a raw function, or an instance of a class that implements operator(), or it could be your lambda holding state.
An alternative is to simply use templates to avoid the potential overhead associated with large lambdas that need to be packaged by std::function.
#include <functional>
using namespace std;
template<typename Callable>
void DoSomething(Callable c) { c(); } // calls the lambda with no args
int main()
{
DoSomething([]{ printf("Hello\n"); });
DoSomething([msg = "World"] { printf("%s\n", msg); });
}
Live Code: http://goo.gl/LMvm3a