convert std::bind to function pointer
Is there any way I can pass the member to the function?
Unless your class object is some kind of global object - it is not possible. Because objects may contain some data, while function pointer is just pointer to function - it doesn't contain any runtime context, only compile-time one.
If you accept having compile-time unique IDs for each callback passing, then you can use following generalized approach.
Usage:
void test(void (*fptr)())
{
fptr();
}
struct SomeStruct
{
int data;
void some_method()
{
cout << data << endl;
}
void another_method()
{
cout << -data << endl;
}
};
int main()
{
SomeStruct local[] = { {11}, {22}, {33} };
test(get_wrapper<0>( boost::bind(&SomeStruct::some_method,local[0]) ));
test(get_wrapper<1>( boost::bind(&SomeStruct::another_method,local[0]) ));
test(get_wrapper<2>( boost::bind(&SomeStruct::some_method,local[1]) ));
test(get_wrapper<3>( boost::bind(&SomeStruct::another_method,local[1]) ));
test(get_wrapper<4>( boost::bind(&SomeStruct::some_method,local[2]) ));
test(get_wrapper<5>( boost::bind(&SomeStruct::another_method,local[2]) ));
}
It may not require Unique ID's for each invocation, for instance because Functors may already have different types, or runtime scope of their usage do not overlap. But it is safer to use unique ID each time.
Implementation:
live demo
#include <boost/optional.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <ostream>
using namespace std;
template<unsigned ID,typename Functor>
boost::optional<Functor> &get_local()
{
static boost::optional<Functor> local;
return local;
}
template<unsigned ID,typename Functor>
typename Functor::result_type wrapper()
{
return get_local<ID,Functor>().get()();
}
template<typename ReturnType>
struct Func
{
typedef ReturnType (*type)();
};
template<unsigned ID,typename Functor>
typename Func<typename Functor::result_type>::type get_wrapper(Functor f)
{
(get_local<ID,Functor>()) = f;
return wrapper<ID,Functor>;
}
// ----------------------------------------------------------------------
void test(void (*fptr)())
{
fptr();
}
struct SomeStruct
{
int data;
void some_method()
{
cout << data << endl;
}
void another_method()
{
cout << -data << endl;
}
};
int main()
{
SomeStruct local[] = { {11}, {22}, {33} };
test(get_wrapper<0>( boost::bind(&SomeStruct::some_method,local[0]) ));
test(get_wrapper<1>( boost::bind(&SomeStruct::another_method,local[0]) ));
test(get_wrapper<2>( boost::bind(&SomeStruct::some_method,local[1]) ));
test(get_wrapper<3>( boost::bind(&SomeStruct::another_method,local[1]) ));
test(get_wrapper<4>( boost::bind(&SomeStruct::some_method,local[2]) ));
test(get_wrapper<5>( boost::bind(&SomeStruct::another_method,local[2]) ));
}
P.S. Beaware of multi-thread access - in such cases you should use some kind of Thread-local storage data.
Can I use std::bind to convert a pointer to member function into a pointer to function?
NathanOliver's comment is correct, and your suspicion is mostly correct. Exactly how pointers to member functions work is not specified, but including this
as a hidden argument mostly works. You just need a bit of extra work for inheritance and pointers to virtual
functions (yes, you can take their address too).
Now, often callbacks include a void*
parameter under your control, which you can use to pass a A*
. In those cases, you can write a wrapper (static
) function that casts the void*
back to A*
and does the actual call to &A::callback
.
That's not the case here. Registration takes a single function, without data. To get this to work in real-life situations, you have to resort to drastic solutions - not portable C++. One such method is to dynamically generate assembly (!). You create - at runtime - the compiled equivalent of
void __trampoline_0x018810000 (int i)
{
A* __this = reinterpret_cast<A*>(0x018810000);
__this->callback(i);
}
As you can see, you have to generate one trampoline for every A*
value, and managing lifetimes of these is a major pain.
How can I store a std::bind function pointer?
You can make use of std::function
. In particular, replace void (*function)()
with std::function<void ()> function
as shown below:
class Context {
private:
//other code here
std::function<void ()> function;
};
Working demo
Get function pointer from std::function when using std::bind
This is quite impossible. The whole reason that std::function
exists is that function pointers suck horrifically and should never, ever, be used by anyone, ever again, except for the doomed souls bearing the Burning Standards of Hell C interoperation, because they cannot handle functions with state.
A std::function<void()>
cannot, in the general case, be converted to a void(*)()
. The only reason this works in the first example is because it happens to be a void(*)()
originally.
how to pass a member function as a function pointer?
You can accomplish this using std::function
and std::bind
:
#include <functional>
#include <iostream>
#include <string>
class Work {
public:
std::function<void(const std::string&)> logger;
void do_sth() { logger("on log"); }
};
class P {
public:
void log(const std::string& s) { std::cout << s; }
};
int main() {
Work w;
P p;
w.logger = std::bind(&P::log, p, std::placeholders::_1);
w.do_sth();
}
Note that function
and bind
may not be in your implementation's standard library yet; you can also get them from the Boost libraries.
Is it possible to change the member function pointer from std::bind to lambda?
It would be possible to do it with your current code by using
func1 = [=](int x, int y){ (pClass->*pFunc)(x,y); };
In my opinion it's probably better to write out the lambda at the calling site instead.
To do that you need to modify setCallback
.
class A
{
public:
template<class T>
void setCallback(T callback);
private:
std::function<void(int, int)> func1;
}
template<class T>
inline void A::setCallback(T callback)
{
func1 = callback;
}
Then we can call from B
s constructor with a lambda.
class B
{
public:
void bFoo(int x, int y);
private:
A a; // instance of class A
}
// Class B - B.cpp
B::B()
{
a.setCallback([&](int x, int y){ bFoo(x, y); }); // & will capture this
}
Related Topics
Convert Between String, U16String & U32String
How to Disassemble a Binary Executable in Linux to Get the Assembly Code
Preparation for Std::Iterator Being Deprecated
Why Are Memcpy() and Memmove() Faster Than Pointer Increments
Is Accessing Data in the Heap Faster Than from the Stack
How to Declare a Global Variable in C++
Accessing Certain Pixel Rgb Value in Opencv
Installing C++ Libraries on Os X
What Does '&' Do in a C++ Declaration
Stack-Buffer Based Stl Allocator
How to Have Multiple Parameter Packs in a Variadic Template
How to Cin Values into a Vector
C++ Equivalent to Java's Blockingqueue