'How to initialize `std::function` with a member-function?
I am trying to learn std::function
and here's my code:
#include <iostream>
#include <functional>
struct Foo {
void print_add(int i){
std::cout << i << '\n';
}
};
typedef std::function<void(int)> fp;
void test(fp my_func)
{
my_func(5);
}
int main(){
Foo foo;
test(foo.print_add);
return 0;
}
Compiler Error:
error: cannot convert 'Foo::print_add' from type 'void (Foo::)(int)' to type 'fp {aka std::function<void(int)>}'
test(foo.print_add);
How can I make this work, i.e how can I pass a member function as a parameter?
Solution 1:[1]
print_add
is a non-static member function of foo
, which means it must be invoked on an instance of Foo
; hence it has an implicit first argument, the this
pointer.
Use a lambda that captures the foo
instance and invokes print_add
on it.
Foo foo;
test([&foo](int i){ foo.print_add(i); });
Another option is to use std::bind
to bind the foo
instance:
test(std::bind(&Foo::print_add, &foo, std::placeholders::_1));
Solution 2:[2]
You need an object to call a non-static member function. Hence, when you want to get a std::function
you have several options:
- make the method static
- bind an object to the function via lambda
- store the object in the
std::function
- pass the object when the
std::function
is called
#include <iostream>
#include <functional>
struct A {
int i = 42;
int get() const { return i; }
static int get_static() { return 0; }
};
struct A_functor {
A a;
int operator()() const { return a.get(); }
};
int main() {
// static method
std::function<int()> f1 = &A::get_static;
std::cout << f1() << "\n";
// bind an object to the function via lambda
A a;
std::function<int()> f2 = [&a](){ return a.get(); };
std::cout << f2() << "\n";
// store the object in the std::function
std::function<int()> f3 = A_functor{};
std::cout << f3() << "\n";
// or
std::function<int()> f4 = [a = A()](){ return a.get(); };
std::cout << f4() << "\n";
// pass the object when the std::function is called
std::function<int(A&)> f5 = &A::get;
std::cout << f5(a) << "\n";
// or
std::function<int(A*)> f6 = &A::get;
std::cout << f6(&a) << "\n";
}
Solution 3:[3]
THE PROBLEM
You cannot directly bind a member-function pointer belonging to type Foo
to std::function<void(int)>
, specifically because calling a non-static member-function requires an instance of type Foo
.
Foo obj; obj.member_function (); // can't call `member_function` without `obj`
Note: You can however bind &Foo::print_add
to std::function<void(Foo&, int)> x;
, and call it as x(instance_of_Foo, arg);
.
Note: It's also possible to bind it to std::function<void(Foo*, int>
, which would require a Foo*
instead of an lvalue of type Foo
.
THE SOLUTION
Instead you can use std::bind
to bind an instance of Foo
to the member-function in question, such as in the below example:
int main(){
Foo foo;
test (std::bind (&Foo::print_add, foo, std::placeholders::_1));
return 0;
}
Above we bind an instance of Foo
named foo
to the member-function pointer &Foo::print_add
.
The usage of std::placeholders::_1
tells std::bind
that we'd like it to generate a function-object that is callable using one (1) argument.
With the above snippet you will have the behaviour that you are currently asking for; my_func(5)
will be equivalent of calling foo.print_add (5)
.
DOCUMENTATION
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 |