I can easily bind member functions to a std::function by wrapping them with a lambda expression with capture clause.
class Class
{
Class()
{
Register([=](int n){ Function(n); });
}
void Register(std::function<void(int)> Callback)
{
}
void Function(int Number)
{
}
};
But I want to bind them directly, something like the following.
// ...
Register(&Class::Function);
// ...
I think according to the C++11 standard, this should be supported. However, in Visual Studio 11 I get these compiler errors.
error C2440: 'newline' : cannot convert from 'int' to 'Class *'
error C2647: '.*' : cannot dereference a 'void (__thiscall Class::* )(int)' on a 'int'
6 Answers 6
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);
9 Comments
Class instance. Which one you pass is up to you.bind(&Class::Function, this, _1) with this information in mind. So, contentually, the bind is obsolete. Is there a technical way to get rid of it or perform the binding inside the function after passing?std::function where you bind to that instance. Then you just re-use that. Actually, there is no need to keep a global std::function. A simple non-member function could do the trick.void foo(int n). Fixed.According to Stephan T. Lavavej - "Avoid using bind(), ..., use lambdas". https://www.youtube.com/watch?v=zt7ThwVfap0&t=32m20s
In this case:
Class()
{
Register([this](int n){ Function(n); });
}
8 Comments
std::function at all... I realize this is not quite as flexible but might be the MOST efficient solution?You can use std::bind:
using namespace std::placeholders; // For _1 in the bind call
// ...
Register(std::bind(&Class::Function, this, _1));
3 Comments
bind then, do I? I haven't the this pointer to find in the parameter list.Register with no arguments that binds to your default function.In C++ 17, you can use:
Register([=](auto && ...args){ return Function(args...); });
which is sweet especially if the argument list is longer long.
Of course the member function's argument list must then be compatible with the std::function's ones.
2 Comments
this via [=] being deprecated.std::forward needed there to make perfect forwarding?With std::function and std::bind, you can treat different class member function the same.
#include <iostream>
#include <functional>
#include <vector>
using namespace std;
using namespace std::placeholders;
class Foo
{
public:
void foo(const string &msg)
{
cout << msg << '\n';
}
};
class Bar
{
public:
void bar(const string &msg, const string &suffix)
{
cout << msg << suffix << '\n';
}
};
int main(int argc, char **argv)
{
Foo foo;
Bar bar;
vector<function<void (const string &msg)>> collection;
collection.push_back(bind(&Foo::foo, &foo, _1));
collection.push_back(bind(&Bar::bar, &bar, _1, "bar"));
for (auto f : collection) {
f("foo");
}
return 0;
}
Comments
As others have already stated, you can use std::bind. The syntax is pretty ugly though. As such, I offer these macros:
#define bindToThis( className, funcName ) \
std::bind( &className::funcName, this, std::placeholders::_1 )
#define bindToThat( className, funcName, objPtr ) \
std::bind( &className::funcName, objPtr, std::placeholders::_1 )
Here's an example implementation of the macro, after first typedefing the std::function to define the required signature (which makes that easier to read/use as well):
typedef std::function<void(const int)> MyIntHandler;
class MyClass
{
public:
MyClass( const MyIntHandler handler );
};
...
SomeOtherClass::SomeOtherClass()
: myObjPtr_( new MyClass(
MyIntHandler( bindToThis( SomeOtherClass, handleSomeInt ) ) )
{}
void SomeOtherClass::handleSomeInt( const int i )
{
// Do something...
}
Comments
Explore related questions
See similar questions with these tags.