I have written a small program where I am trying to pass a pointer to member function of a class to another function. Can you please help me and where I am going wrong..?
#include<iostream>
using namespace std;
class test{
public:
typedef void (*callback_func_ptr)();
callback_func_ptr cb_func;
void get_pc();
void set_cb_ptr(void * ptr);
void call_cb_func();
};
void test::get_pc(){
cout << "PC" << endl;
}
void test::set_cb_ptr( void *ptr){
cb_func = (test::callback_func_ptr)ptr;
}
void test::call_cb_func(){
cb_func();
}
int main(){
test t1;
t1.set_cb_ptr((void *)(&t1.get_pc));
return 0;
}
I get the following error when I try to compile it.
error C2276: '&' : illegal operation on bound member function expression
You cannot cast a function pointer to void*.
If you want a function pointer to point to a member function you must declare the type as
ReturnType (ClassType::*)(ParameterTypes...)
Further you cannot declare a function pointer to a bound member function, e.g.
func_ptr p = &t1.get_pc // Error
Instead you must get the address like this:
func_ptr p = &test::get_pc // Ok, using class scope.
Finally, when you make a call to a function pointer pointing to a member function, you must call it with an instance of the class that the function is a member of. For instance:
(this->*cb_func)(); // Call function via pointer to current instance.
Here's the full example with all changes applied:
#include <iostream>
class test {
public:
typedef void (test::*callback_func_ptr)();
callback_func_ptr cb_func;
void get_pc();
void set_cb_ptr(callback_func_ptr ptr);
void call_cb_func();
};
void test::get_pc() {
std::cout << "PC" << std::endl;
}
void test::set_cb_ptr(callback_func_ptr ptr) {
cb_func = ptr;
}
void test::call_cb_func() {
(this->*cb_func)();
}
int main() {
test t1;
t1.set_cb_ptr(&test::get_pc);
t1.call_cb_func();
}
In addition to Snps's answer, you could also use a function wrapper from C++11 to store a lambda function:
#include <iostream>
#include <functional>
class test
{
public:
std::function<void ()> Func;
void get_pc();
void call_cb_func();
void set_func(std::function<void ()> func);
};
void test::get_pc()
{
std::cout << "PC" << std::endl;
}
void test::call_cb_func()
{
Func();
}
void test::set_func(std::function<void ()> func)
{
Func = func;
}
int main() {
test t1;
t1.set_func([&](){ t1.get_pc(); });
t1.call_cb_func();
}
Related
One of my class member function needs other member functions as arguments. I learnt that the member function pointer or lambda expression can pass the member function to another member function. I did this in my class declaration:
class A
{
public:
void run();
private:
double objfun1();
double objfun2();
.... // and other object function added here
template <typename Callable>
fun_caller(Callable obj_call);
};
When I need to pass different object functions to fun_caller in the public function A::run(), I first define the lambda expression:
void run()
{
... //some code blocks
auto obj_call = [this](){return objfun1();};
fun_caller(obj_call);
... // some code blocks
}
The compiler reports error.
error C2297: '->*': illegal, right operand has type 'Callable'
What's wrong with my lambda expression?
Thank you very much!!
This works:
#include <iostream>
class A
{
public:
void run();
private:
double objfun1(){ return 1.; }
double objfun2(){ return 2.; }
template <typename Callable>
void fun_caller(Callable obj_call){
std::cout << "called: " << obj_call() << "\n";
}
};
void A::run(){
auto obj_call = [this](){return objfun1();};
fun_caller(obj_call);
}
int main(){
A obj;
obj.run();
}
I have written a small program where I am trying to pass a pointer to member function of a class to another function. Can you please help me and where I am going wrong..?
#include<iostream>
using namespace std;
class test{
public:
typedef void (*callback_func_ptr)();
callback_func_ptr cb_func;
void get_pc();
void set_cb_ptr(void * ptr);
void call_cb_func();
};
void test::get_pc(){
cout << "PC" << endl;
}
void test::set_cb_ptr( void *ptr){
cb_func = (test::callback_func_ptr)ptr;
}
void test::call_cb_func(){
cb_func();
}
int main(){
test t1;
t1.set_cb_ptr((void *)(&t1.get_pc));
return 0;
}
I get the following error when I try to compile it.
error C2276: '&' : illegal operation on bound member function expression
You cannot cast a function pointer to void*.
If you want a function pointer to point to a member function you must declare the type as
ReturnType (ClassType::*)(ParameterTypes...)
Further you cannot declare a function pointer to a bound member function, e.g.
func_ptr p = &t1.get_pc // Error
Instead you must get the address like this:
func_ptr p = &test::get_pc // Ok, using class scope.
Finally, when you make a call to a function pointer pointing to a member function, you must call it with an instance of the class that the function is a member of. For instance:
(this->*cb_func)(); // Call function via pointer to current instance.
Here's the full example with all changes applied:
#include <iostream>
class test {
public:
typedef void (test::*callback_func_ptr)();
callback_func_ptr cb_func;
void get_pc();
void set_cb_ptr(callback_func_ptr ptr);
void call_cb_func();
};
void test::get_pc() {
std::cout << "PC" << std::endl;
}
void test::set_cb_ptr(callback_func_ptr ptr) {
cb_func = ptr;
}
void test::call_cb_func() {
(this->*cb_func)();
}
int main() {
test t1;
t1.set_cb_ptr(&test::get_pc);
t1.call_cb_func();
}
In addition to Snps's answer, you could also use a function wrapper from C++11 to store a lambda function:
#include <iostream>
#include <functional>
class test
{
public:
std::function<void ()> Func;
void get_pc();
void call_cb_func();
void set_func(std::function<void ()> func);
};
void test::get_pc()
{
std::cout << "PC" << std::endl;
}
void test::call_cb_func()
{
Func();
}
void test::set_func(std::function<void ()> func)
{
Func = func;
}
int main() {
test t1;
t1.set_func([&](){ t1.get_pc(); });
t1.call_cb_func();
}
I have a C-style function, which stores another function as an argument. I also have an object, which stores a method that must be passed to the aforementioned function. I built an example, to simulate the desired situation:
#include <functional>
#include <iostream>
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
std::function<void(int)> f;
void foo(int i) {
std::cout << i << "\n";
}
};
int main() {
TestClass t;
t.f = std::bind(&TestClass::foo, &t, std::placeholders::_1);
foo( t.f.target<void(int)>() );
return 0;
}
What is expected is that it will be shown on screen "2". But I'm having trouble compiling the code, getting the following message on the compiler:
error: const_cast to 'void *(*)(int)', which is not a reference, pointer-to-object, or pointer-to-data-member
return const_cast<_Functor*>(__func);
As I understand the use of "target", it should return a pointer in the format void () (int), related to the desired function through std :: bind. Why didn't the compiler understand it that way, and if it is not possible to use "target" to apply what I want, what would be the alternatives? I don't necessarily need to use std :: function, but I do need the method to be non-static.
This is a dirty little hack but should work
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
void foo(int i) {
std::cout << i << "\n";
}
};
static TestClass* global_variable_hack = nullptr;
void hacky_function(int x) {
global_variable_hack->foo(x);
}
int main() {
TestClass t;
global_variable_hack = &t;
foo(hacky_function);
return 0;
}
//can also be done with a lambda without the global stuff
int main() {
static TestClass t;
auto func = [](int x) {
t->foo(x); //does not need to be captured as it is static
};
foo(func); //non-capturing lambas are implicitly convertible to free functions
}
I want to pass a method as an argument to a method which takes an int and returns void:
void A::SetCallback(void (*callback)(int))
{
.....................
}
void B::test()
{
a->SetCallback(&B::Done); //
}
void B::Done(int i)
{
..........................
}
Inside test() I get this error:
Error 1 error C2664: cannot convert parameter 1 from 'void (__thiscall B::* )(int)' to 'void (__cdecl *)(int)'
I saw some example on StackOverflow how to fix this but it uses elements from C++11, to which I do not have access.
How can I fix this using C++03 ?
You cannot pass a non-static method to a function that takes a pointer to a function. Functions and methods are two completely different things. In order to invoke a non-static method you have to, obviously, have an object whose method you're invoking.
If, in your example, Done() is a static class method, then, yes, you can pass it this way, since a static class method is just another name for a function.
It is possible to have a pointer to a class method:
void A::SetCallback(void (B::*callback)(int))
{
}
void B::test()
{
a->SetCallback(&B::Done); //
}
void B::Done(int i)
{
..........................
}
But in order to invoke the class method, you need an object whose method to invoke:
B *object=give_me_a_pointer_to_b_from_somewhere();
(object->*callback)(0);
&ClassName::method_name creates the pointer and void(ClassName::*)(int, char*) is the type.
void go(void(ClassName::*parameter_name)(int, char*));
go(&ClassName::method_name);
You cannot pass a pointer to class method (which is of type void (B::*) (int) in your case) to a pointer to a free function.
What would happen if you could?
void f (void (*g) (int)) {
g(2);
}
struct A {
int x;
void foo (int c) { x += c; }
};
f(&A::foo); // Oh oh! Where will I find `x` in the call `g(2)`?
If you only want pointer to method of B, you need to change the callback type:
void A::SetCallback(void (B::*callback)(int)) { }
But then you need an instance of B to call your callback, e.g.:
B b;
(b.*callback)(2);
I'm using following code. It is not pretty, but you asking for C++03:
#include <iostream>
#include <vector>
#include <functional>
class AbstractCallback {
public:
virtual void call(int arg) = 0;
};
template <class T>
class Callback : public AbstractCallback {
public:
typedef std::mem_fun1_t<void, T, int> CallbackFunc;
private:
CallbackFunc func;
T* object;
public:
Callback(T* _object, const CallbackFunc& _func)
: object(_object), func(_func) {
}
void call(int arg) {
func(object, arg);
}
};
struct A {
void foo(int a) {
std::cout << "foo " << a << std::endl;
}
};
struct B {
void bar(int a) {
std::cout << "bar " << a << std::endl;
}
};
int main() {
A a;
B b;
AbstractCallback* cbs[2] = {
new Callback<A>(&a, std::mem_fun(&A::foo)),
new Callback<B>(&b, std::mem_fun(&B::bar)),
};
cbs[0]->call(10);
cbs[1]->call(22);
delete cbs[0];
delete cbs[1];
return 0;
}
As you can see pointer-to member functions (of type A::* and B::*) are wrapped into std::mem_funs and a Callback class which is generated for each type (A and B in this case).
This allows to keep method of any type in vectors, arrays or lists of abstract callbacks.
I'm trying to run a method of one class from inside another class, I have a basic GUI that lets the user fill his name and password, and when it clicks the login button another takes over and handles the event, I would like to set a callback in case of a successful login, but I'm having problems sending the function pointer to my handler.
I made a raw example of what I'm trying to do.
#include <iostream>
using namespace std;
class LoginHandler {
public:
void loginAttempt(bool result)
{
if(result == true)
{
cout << "Login success! W00t!" << endl;
//Run my callback :)
callback();
} else {
cout << "Login failed." << endl;
}
}
void setCallback(void (*cb)())
{
callback = cb;
}
private:
void (*callback)();
};
class Foo {
public:
void run()
{
LoginHandler* loginHandler = new LoginHandler();
loginHandler->setCallback(&Foo::sayHello);
loginHandler->loginAttempt(false);
loginHandler->loginAttempt(true);
}
void sayHello()
{
cout << "You actually logged in! Isn't that amazing!?" << endl;
}
};
int main()
{
Foo foo;
foo.run();
return 0;
}
I'm getting the next error:
In member function 'void Foo::run()':
error: no matching function for call to 'LoginHandler::setCallback(void (Foo::*)())'
note: candidate is: void LoginHandler::setCallback(void (*)())
note: no known conversion for argument 1 from 'void (Foo::*)()' to 'void (*)()'
Thanks in advice.
Raw function pointers are mostly obsolete and should be used only for low-level performance-critical stuff. For the rest of us C++ has std::function which is infinitely better. It handles cases like yours with ease.
If you cannot use a it because you don't have a C++11 compiler, boost::function is a drop-in substitute.
You've specified that "setCallback" takes a function pointer, not a member-function pointer.
void setCallback(void (*cb)())
you are calling it - as the compiler complains - with a member-function pointer
loginHandler->setCallback(&Foo::sayHello);
In order to take a member function pointer, the setCallback definition is going to have to be able to determine what class to use, and the location where you call the callback is going to have to know what class so it can dereference the pointer.
Generally people solve this with a C-style callback handler, either
static FooSayHelloCallback(void* fooParam)
{
Foo* foo = static_cast<Foo*>(fooParam);
foo->sayHello();
}
or a functor object
struct LoginHandlerCallbackFunctor
{
void* m_this;
public:
FooSayHelloFunctor(void* this_) : m_this(this_) {}
virtual void operator()() = 0;
};
struct FooSayHelloFunctor : public LoginHandlerCallbackFunctor
{
public:
FooSayHelloFunctor(Foo* foo_) : LoginHandlerCallbackFunctor(foo_) {}
virtual void operator()() { ((Foo*)m_this)->sayHello(); }
};
Then
class LoginHandler {
...
LoginHandlerCallbackFunctor m_callback;
...
void setCallback(const LoginHandlerCallbackFunctor& functor)
{
m_callback = functor;
}
void doCallback()
{
m_callback(); // calls operator()
}
If you want to get really fancy you could maybe do that with templates.
Or, alternatively, you could use C++11 Lambdas and std::function.
class LoginHandler
{
typedef std::function<void(void)> GreetingCallback;
GreetingCallback m_callback;
...
void setCallback(const GreetingCallback& callback_)
{
m_callback = callback_;
}
void doCallback()
{
m_callback();
}
}
and in foo
LoginHandler loginHandler();
loginHandler.setCallback([=]() { sayHello(); });
loginHandler->loginAttempt(false);
loginHandler->loginAttempt(true);
sayHello should be a static function.
Because ordinary member functions have implicit parameter ¨this¨. So the full signature of sayHello is void sayHello(Foo* this);
Another way - use pointer to class member.
Also you can use functor structure instead of function.