When using std::bind
to bind a member function, the first argument is the objects this
pointer. However it works passing the object both as a pointer and not.
See for example the following program:
#include <iostream> #include <functional> struct foo { void bar(int v) { std::cout << "foo::bar - " << v << '\n'; } }; int main() { foo my_foo; auto f1 = std::bind(&foo::bar, my_foo, 1); auto f2 = std::bind(&foo::bar, &my_foo, 2); f1(); f2(); }
Both clang and GCC compiles this without complaints, and the result works for both binds:
foo::bar - 1 foo::bar - 2
I have been trying to wrap my head around the specification (section 20.8.9) but it's one of the places where it's far from clear to me.
Should only one be correct, or are both correct?
The pointer to member operators . * and ->* are used to bind a pointer to a member of a specific class object. Because the precedence of () (function call operator) is higher than . * and ->* , you must use parentheses to call the function pointed to by ptf .
You can use pointers to member functions in the same manner as pointers to functions. You can compare pointers to member functions, assign values to them, and use them to call member functions.
std::bind. std::bind is a Standard Function Objects that acts as a Functional Adaptor i.e. it takes a function as input and returns a new function Object as an output with with one or more of the arguments of passed function bound or rearranged.
Bind function with the help of placeholders helps to manipulate the position and number of values to be used by the function and modifies the function according to the desired output.
Both are correct. 20.8.9.1.2 forwards to 20.8.2 to describe the requirements and the effect of your call to bind
. 20.8.2 is:
20.8.2 Requirements [func.require]
1 Define INVOKE
(f, t1, t2, ..., tN)
as follows:—
(t1.*f)(t2, ..., tN)
whenf
is a pointer to a member function of a classT
andt1
is an object of typeT
or a reference to an object of typeT
or a reference to an object of a type derived fromT
;—
((*t1).*f)(t2, ..., tN)
whenf
is a pointer to a member function of a classT
andt1
is not one of the types described in the previous item;—
t1.*f
whenN == 1
andf
is a pointer to member data of a classT
andt1
is an object of typeT
or a reference to an object of typeT
or a reference to an object of a type derived fromT
;—
(*t1).*f
whenN == 1
andf
is a pointer to member data of a classT
andt1
is not one of the types described in the previous item;—
f(t1, t2, ..., tN)
in all other cases.
The first two options allow both a reference and a pointer.
The important thing to notice here is that the wording does not limit you to plain pointers. You could use a std::shared_ptr
or some other smart pointer to keep your instance alive while bound and it would still work with std::bind
as t1
is dereferenced, no matter what it is (given, of course, that it's possible).
To add to the correct answer (that both forms are allowed).
I think of the two binding options in analogy with function argument declaration, which may be "passed by value" or "passed by reference".
In the case of f1
(aka passing my_foo
"by value") the result doesn't "see" any changes made to my_foo
past the binding point. This may not be desired especially if my_foo
evolves. "By value" binding has an additional "cost" of (several) calls to a copy constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With