As shown in the code and output below, three phenomena can be observed:
f1
in the code, whether it is passed ff
or &ff
, the num_
value in the ff
object can be modified normally after execution.ff
is bound in advance, the num_
value in ff
object is not modified after execution; If you use placeholder to pass ff
or bound &ff
directly, it can be modified as normal.Foo
, then ff
is passed, and the num_
value in the ff
object is not modified after execution.So my problem is that all callable objects are called just like INVOKE(f, t1, t2, ..., tN)
. Why do the above three differences occur ?
#include <cstdio>
#include <functional>
#include <iostream>
using namespace std;
struct Foo
{
Foo(int num) : num_(num) {}
void print_add(int i) { num_ += i;}
int num_;
};
int main()
{
// cout << "check mem_fn" << endl;
Foo ff(1);
auto f1 = std::mem_fn(&Foo::print_add);
f1(ff, 1);
cout << "mem_fn pass ff, after exec, ff num : " << ff.num_ << endl;
f1(&ff, 1);
cout << "mem_fn pass &ff, after exec, ff num : " << ff.num_ << endl;
auto f2 = std::bind(&Foo::print_add, placeholders::_1, placeholders::_2);
f2(ff, 1);
cout << "bind use placeholder_1 to pass ff, after exec, ff num : " << ff.num_ << endl;
std::function<void(int)> f3 = std::bind(&Foo::print_add, ff, placeholders::_1);
f3(1);
cout << "bind pass ff, after exec, ff num : " << ff.num_ << endl;
std::function<void(int)> f4 = std::bind(&Foo::print_add, &ff, placeholders::_1);
f4(1);
cout << "bind pass &ff, after exec, ff num : " << ff.num_ << endl;
auto f5 = std::bind(f1, placeholders::_1, placeholders::_2);
f5(ff, 1);
cout << "bind_mem_fn pass ff, after exec, ff num : " << ff.num_ << endl;
auto f6 = std::bind(f1, placeholders::_1, placeholders::_2);
f6(&ff, 1);
cout << "bind_mem_fn pass &ff, after exec, ff num : " << ff.num_ << endl;
std::function<void(Foo, int)> f7 = &Foo::print_add;
f7(ff, 1);
cout << "function(Foo), pass ff, after exec, ff num : " << ff.num_ <<endl;
std::function<void(Foo*, int)> f8 = &Foo::print_add;
f8(&ff, 1);
cout << "function(Foo*), pass ff*, after exec, ff num : " << ff.num_ <<endl;
}
The output like this:
mem_fn pass ff, after exec, ff num : 2
mem_fn pass &ff, after exec, ff num : 3
bind use placeholder_1 to pass ff, after exec, ff num : 4
bind pass ff, after exec, ff num : 4
bind pass &ff, after exec, ff num : 5
bind_mem_fn pass ff, after exec, ff num : 6
bind_mem_fn pass &ff, after exec, ff num : 7
function(Foo), pass ff, after exec, ff num : 7
function(Foo*), pass ff*, after exec, ff num : 8
What you observe is the difference between making a copy of ff
and not making a copy. In all cases, the callables call the member function and the member is modified. Only sometimes you do not see the modification on ff
because the modification is on a copy of ff
.
Here:
std::function<void(Foo, int)> f7 = &Foo::print_add;
f7(ff, 1);
// ^^ passed by value
a copy is made. And here
std::function<void(int)> f3 = std::bind(&Foo::print_add, ff, placeholders::_1);
// passed by value ^^
as well.
The difference boils down to the difference between those two:
void make_a_copy(Foo f) {
f.print_add(1);
}
void pass_by_ref(Foo& f) {
f.print_add(1);
}
Calling those two looks the same just like f1(ff,1)
and f7(ff,1)
looks the same, but they do something different:
Foo ff;
make_a_copy(ff); // modifies a copy of ff
pass_by_ref(ff); // modifies ff itself