How Std::Bind Works with Member Functions

How std::bind works with member functions

When you say "the first argument is a reference" you surely meant to say "the first argument is a pointer": the & operator takes the address of an object, yielding a pointer.

Before answering this question, let's briefly step back and look at your first use of std::bind() when you use

std::bind(my_divide, 2, 2)

you provide a function. When a function is passed anywhere it decays into a pointer. The above expression is equivalent to this one, explicitly taking the address

std::bind(&my_divide, 2, 2)

The first argument to std::bind() is an object identifying how to call a function. In the above case it is a pointer to function with type double(*)(double, double). Any other callable object with a suitable function call operator would do, too.

Since member functions are quite common, std::bind() provides support for dealing with pointer to member functions. When you use &print_sum you just get a pointer to a member function, i.e., an entity of type void (Foo::*)(int, int). While function names implicitly decay to pointers to functions, i.e., the & can be omitted, the same is not true for member functions (or data members, for that matter): to get a pointer to a member function it is necessary to use the &.

Note that a pointer to member is specific to a class but it can be used with any object that class. That is, it is independent of any particular object. C++ doesn't have a direct way to get a member function directly bound to an object (I think in C# you can obtain functions directly bound to an object by using an object with an applied member name; however, it is 10+ years since I last programmed a bit of C#).

Internally, std::bind() detects that a pointer to a member function is passed and most likely turns it into a callable objects, e.g., by use std::mem_fn() with its first argument. Since a non-static member function needs an object, the first argument to the resolution callable object is either a reference or a [smart] pointer to an object of the appropriate class.

To use a pointer to member function an object is needed. When using a pointer to member with std::bind() the second argument to std::bind() correspondingly needs to specify when the object is coming from. In your example

std::bind(&Foo::print_sum, &foo, 95, _1)

the resulting callable object uses &foo, i.e., a pointer to foo (of type Foo*) as the object. std::bind() is smart enough to use anything which looks like a pointer, anything convertible to a reference of the appropriate type (like std::reference_wrapper<Foo>), or a [copy] of an object as the object when the first argument is a pointer to member.

I suspect, you have never seen a pointer to member - otherwise it would be quite clear. Here is a simple example:

#include <iostream>

struct Foo {
int value;
void f() { std::cout << "f(" << this->value << ")\n"; }
void g() { std::cout << "g(" << this->value << ")\n"; }
};

void apply(Foo* foo1, Foo* foo2, void (Foo::*fun)()) {
(foo1->*fun)(); // call fun on the object foo1
(foo2->*fun)(); // call fun on the object foo2
}

int main() {
Foo foo1{1};
Foo foo2{2};

apply(&foo1, &foo2, &Foo::f);
apply(&foo1, &foo2, &Foo::g);
}

The function apply() simply gets two pointers to Foo objects and a pointer to a member function. It calls the member function pointed to with each of the objects. This funny ->* operator is applying a pointer to a member to a pointer to an object. There is also a .* operator which applies a pointer to a member to an object (or, as they behave just like objects, a reference to an object). Since a pointer to a member function needs an object, it is necessary to use this operator which asks for an object. Internally, std::bind() arranges the same to happen.

When apply() is called with the two pointers and &Foo::f it behaves exactly the same as if the member f() would be called on the respective objects. Likewise when calling apply() with the two pointers and &Foo::g it behaves exactly the same as if the member g() would be called on the respective objects (the semantic behavior is the same but the compiler is likely to have a much harder time inlining functions and typically fails doing so when pointers to members are involved).

How to directly bind a member function to an std::function in Visual Studio 11?


I think according to the C++11 standard, this should be supported

Not really, because a non-static member function has an implicit first parameter of type (cv-qualified) YourType*, so in this case it does not match void(int). Hence the need for std::bind:

Register(std::bind(&Class::Function, PointerToSomeInstanceOfClass, _1));

For example

Class c;
using namespace std::placeholders; // for _1, _2 etc.
c.Register(std::bind(&Class::Function, &c, _1));

Edit You mention that this is to be called with the same Class instance. In that case, you can use a simple non-member function:

void foo(int n)
{
theClassInstance.Function(n);
}

then

Class c;
c.Register(foo);

std::bind with member function and this in c++

Let the compiler deduce types based on passed arguments:

std::function<void(void)> function2 = std::bind(&Class2::print, this);

above is enough.

Version with explicit template arguments list looks like:

std::function<void(void)> function3 = std::bind<void(Class2::*)(),Class2*>(&Class2::print, this);

// std::bind<void(Class2::*)(),Class2*>
/ \ / \
| |---- pointer to type of object instance you invoke member function
|--- pointer to member function

Demo

std::bind of class member function

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

Why can std::function bind functions of different types?


func_type has two parameters, and Test::state_function only has one parameter,I can't understand how it works.

For binding purposes, the non-static member function state_function has an additional first implicit object parameter of type const Test&.

Now, when we define a std::function object, we specify the function type that is the signature of the callable object that object can represent. When the callable is a member function, the signature’s first parameter represent the (normally implicit) object on which the member function will be called on. Now, there are two ways to specify the signature in case of a member function:

Method 1

Here we say that the object on which the member function will be called will be passed as a pointer.

//----------------------------------vvvvv-------------------------->pointer here means a pointer to the object of type `Test` will be passed
using func_type = std::function<int(Test* const, const double)>;

This method 1 is what you used in your example. It means that the member function was being called using a pointer to an object of type Test.

Method 2

But there is another way of passing the object. In particular, you can sepcify that the object will be passed as a reference as shown below:

//----------------------------------------vvvvv------------------>note the reference here which says that here an object of type `Test` will be passed instead of a pointer 
using func_type = std::function<int(const Test&, const double)>;

Note also that for the above to work you will have to modify it->second(this, 0.0); to

//---------vvvvv-------------->note the * used here to dereference 
it->second(*this, 0.0);

Demo

std::bind member function within struct

The first (hidden) argument of a argument of a member function is the this variable. So the correct way to use std::bind here is

std::function<int(int)> wrapper = std::bind(&Foo::f1, this, _1 , 7);

However, modern C++, the correct way to do this is to use a lambda. I usually use explicit binds for this, so:

auto wrapper = [this](V v) {
return f1(v, 7);
}


Related Topics



Leave a reply



Submit