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?
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));
Live demo
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";
}
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
std::function - cppreference.com
std::bind - cppreference.com
std::placeholders - cppreference.com
Related
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?
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));
Live demo
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";
}
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
std::function - cppreference.com
std::bind - cppreference.com
std::placeholders - cppreference.com
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?
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));
Live demo
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";
}
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
std::function - cppreference.com
std::bind - cppreference.com
std::placeholders - cppreference.com
void foo(int a) {
cout << "Hello" << a << '\n';
}
according to rule of decltype, the type of decltype(foo) should be "void foo(int)",
but it seems we can do nothing with it:
void (& f_ref)(int) = foo;
void (* f_ptr)(int) = foo;
cout<<is_same_v<decltype(foo), decltype(f_ref)><<endl; //return 0
cout<<is_same_v<decltype(foo), decltype(f_ptr)><<endl; //return 0
decltype(foo) df;
df = foo; //error: assignment of function ‘void df(int)’
df = &foo; //error: assignment of function ‘void df(int)’
decltype(foo) df{foo}; //error: function ‘void df(int)’ is initialized like a variable
decltype(foo) df{&foo}; //error: function ‘void df(int)’ is initialized like a variable
Two is_same_v in your snippets are evaluated as 0 because, well, the types are different.
dectype(foo) is void (int) (not void foo(int), the name is not a part of the type),
which is different from void (&)(int) (the type of f_ref) and void (*)(int) (the type of f_ptr).
This line:
decltype(foo) df{foo};
doesn't compile just because the syntax doesn't allow you to have initializers in function declarations.
Even without the decltype it doesn't work:
void df(int) {foo}; // error: expected ';' before '}' token
Though you can create a pointer to decltype(foo):
decltype(foo) *df{foo}; // Becomes `void (*df)(int) {foo};`
These lines:
df = foo;
df = &foo;
don't compile because you can't assign to functions. It wouldn't work even if df was void df(int);.
How can I use this type?
There are countless uses. E.g. you can use it to create pointers to this function as mentioned above, or it can be used as a template parameter (for std::function or something else).
Declare a variable:
decltype(foo)* pf = foo;
pf(42);
Use a std::function function wrapper:
std::function<decltype(foo)> f = foo;
f(42);
You can use it to declare functional object that would have the same signature as a function:
using ffoo = ::std::function<decltype(foo)>;
Is the return type of decltype(function_name) totally useless?
Definitely not. Live example
void f1();
void f2(int);
void f3();
int main()
{
std::cout << "f1 - f2 " << std::is_same<decltype(f1),decltype(f2)>::value << std::endl;
std::cout << "f1 - f3 " << std::is_same<decltype(f1),decltype(f3)>::value << std::endl;
}
this can be used with std::enable_if for example.
In this statement
cout<<is_same_v<decltype(foo), decltype(f_ref)><<endl;
the left template argument is a function type while the right template argument is a referenced type. To compare the types you should remove the reference.
In this statement
cout<<is_same_v<decltype(foo), decltype(f_ptr)><<endl;
there is compared a function type with a pointer to a function.
Thus the both statement returns 0 (false).
These statements
df = foo;
df = &foo;
do not make sense. You may not assign functions.
And these statements
decltype(foo) df{foo};
decltype(foo) df{&foo};
also do not make sense.
You can declare a function of the type decltype( foo ) for example in a class and then define it.
Here is a demonstrative program.
#include <iostream>
#include <type_traits>
void foo( int a )
{
std::cout << "Hello " << a << '\n';
}
struct A
{
decltype(foo) df;
};
void A::df( int a )
{
std::cout << "Bye " << a << '\n';
}
int main()
{
foo( 0 );
A a;
a.df( 1 );
void (& f_ref)(int) = foo;
void (* f_ptr)(int) = foo;
std::cout << std::is_same<decltype(&foo), decltype( f_ptr )>() << std::endl;
std::cout << std::is_same<decltype(foo), std::remove_reference_t<decltype( f_ref )>>() << std::endl;
return 0;
}
Its output is
Hello 0
Bye 1
1
1
Take into account that in this declaration
void (& f_ref)(int) = foo;
the function designator foo is implicitly converted to a pointer to the function.
This is exactly as it should be. If you wrote void(int) df;, that is obviously wrong. You are attempting to declare a variable with a function type, which doesn't make sense. The only context where this might make sense is to declare a function object: auto bar = std::function<decltype(foo)>;
Now bar is an object which refers to a function (or function-like instance such as a lambda) with the type void(int).
My plan is to build several listener classes which own predefined "callback hooks".
In the example below class Foo has a "callback hook" called onChange. It will be set to a default callback function during construction. It can also be set to an arbitrary function which provides the correct interface, like shown with the object f1 and the function callback().
The problem is when I want to call the object member onChange inside the for-loop the compiler says that I provide to much arguments. i am aware of the problem that i don't provide a member function to the std::mem_fn but instead an object member which is a function wrapper.
How do I manage to pass the argument to the std::function member object of class Foo without using std::bind and use std::mem_fn instead like shown in the example?
struct Foo
{
Foo()
{
// default callback
onChange = [](int value)
-> void { std::cerr << "Foo::onChange( " << value << " )" << std::endl; };
}
// class destructor
virtual ~Foo() {}
std::function<void(int value)> onChange;
};
void callback(int value)
{
std::cerr << "callback( " << value << " )" << std::endl;
}
int main()
{
Foo f0;
Foo f1;
f1.onChange = callback;
auto vec = std::vector<Foo>();
vec.push_back(f0);
vec.push_back(f1);
auto func_wrapper = std::mem_fn( &Foo::onChange );
for (auto f : vec)
{
func_wrapper(f, 42);
}
}
I have this code:
#include <iostream>
#include <functional>
struct Foo
{
int get(int n) { return 5+n; }
};
int main()
{
Foo foo;
auto L = std::bind(&Foo::get, &foo, 3);
std::cout << L() << std::endl;
return 0;
}
Seems that this:
auto L = std::bind(&Foo::get, &foo, 3);
is equivalento to:
auto L = std::bind(&Foo::get, foo, 3);
Why?
std::bind() accepts its arguments by value. This means that in the first case you are passing a pointer by value, resulting in the copy of a pointer. In the second case, you are passing an object of type foo by value, resulting in a copy of an object of type Foo.
As a consequence, in the second case the evaluation of the expression L() causes the member function get() to be invoked on a copy of the original object foo, which may or may not be what you want.
This example illustrates the difference (forget the violation of the Rule of Three/Rule of Five, this is just for illustration purposes):
#include <iostream>
#include <functional>
struct Foo
{
int _x;
Foo(int x) : _x(x) { }
Foo(Foo const& f) : _x(f._x)
{
std::cout << "Foo(Foo const&)" << std::endl;
}
int get(int n) { return _x + n; }
};
int main()
{
Foo foo1(42);
std::cout << "=== FIRST CALL ===" << std::endl;
auto L1 = std::bind(&Foo::get, foo1, 3);
foo1._x = 1729;
std::cout << L1() << std::endl; // Prints 45
Foo foo2(42);
std::cout << "=== SECOND CALL ===" << std::endl;
auto L2 = std::bind(&Foo::get, &foo2, 3);
foo2._x = 1729;
std::cout << L2() << std::endl; // Prints 1732
}
Live example.
If, for any reason, you don't want to use the pointer form, you can use std::ref() to prevent a copy of the argument from being created:
auto L = std::bind(&Foo::get, std::ref(foo), 3);
They are not the same. The generic function binder std::bind copies it's arguments. In the case of std::bind(&Foo::get,&foo,3), the pointer is copied, but when you call the bound object it still applies to the original foo object. In std::bind(&Foo::get,foo,3) the object foo is copied, and the later call applies to the bound copy, not to the original object.
You can test this by using a member function that accesses internal state of the object, bind the object in both ways, change the original object and see how the results differ.