C++ Function Pointer Casting

Started by
6 comments, last by Muzzy A 9 years, 7 months ago

Hey,

I'm trying to set up a function pointer so that ANY function can be passed to it as long as it's the same signature.

Example

 
// Define a simple function pointer
typedef void (*FuncPointer)();
 
void someFunc()
{
}
 
int main()
{
    FuncPointer func = someFunc;
 
    func();
}
 
// This works no prob
 
 
// Now here is what I want to do
class A
{
public:
    void foo();
};
 

// Define a simple function pointer
typedef void (*FuncPointer)();

 
int main()
{
    // This is what I want to work
    FuncPointer func = A::foo;
 
    // I want it to work without having to define a function pointer like this
   typedef void (A::*FunctionPointer)()
 
/*
    IS THIS POSSIBLE?
*/
 
    func();
}
 
Advertisement

Consider the hypothetical call to func() in your last example; what is the value of the this pointer inside A::foo() once func() is called? In other words, which object do you expect the member function to be called on?

The moral of the story is: you expect it work work as long as the functions have the same signature, but someFunc() and A::foo() are fundamentally different.

I know this, let me clarify


class A
{
public:
    void foo();
};
 

// Define a simple function pointer
typedef void (*Func)();

 
int main()
{
    A obj;

    // This is what I want to work
    Func func = obj.foo;
 
    func();
}
 

I want to be able to have access to that object inside the function that gets called from the function pointer so that I don't have to have some sort of global reference to 'obj'

you can't typecast it to a 'Func', it gives an error as well.

The whole reason is I have a button class which has a function pointer that it calls when the button is clicked, and the function that gets passed to it is a 'void (*Func)()'. I want to be able to have access to the class that holds that button without having to create some static/global variable to get access to it.


I want to be able to have access to that object inside the function that gets called from the function pointer so that I don't have to have some sort of global reference to 'obj'

You don't, not with standard function pointers like this. Member function pointers are different beasts. In the old C days you would idiomatically do this kind of thing by having your code take a void* "user data" pointer, which would then be passed along to the callback function, so that your callback could have non-global state, which I suppose is what you are trying to achieve. Something like set_callback(func_ptr, &foo) and then use the pointer to your class instance from the callback parameters. In C++, you probably want to use the modern C++ features like std::function, bind, lambdas, etc... which handle all of this and more.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

OK I'll look those up, thanks for the help

The example would become:

using FuncWrapper = std::function<void()>;

void someFunc()
{
}

class A
{
public:
    void foo();
};
 
int main()
{
    // free function
    FuncWrapper func = someFunc;
    func();

    // member via lambda
    A obj;
    func = [&](){ obj.foo(); };
    func();

    // member via std::bind (there's also a Boost version if your compiler is ancient)
    func = std::bind(std::mem_fn(&A::foo), &obj);
    func();
}
You can also have std::function, lambdas, or std::bind using arguments and return values by spelling out the signature, e.g. std::function<result_type(param_type1, param_type2)> and then adding the forwarding params to the lambda or the placeholders (std::_1, std::_2, etc.) to std::bind.

Sean Middleditch – Game Systems Engineer – Join my team!

The example would become:


using FuncWrapper = std::function<void()>;

void someFunc()
{
}

class A
{
public:
    void foo();
};
 
int main()
{
    // free function
    FuncWrapper func = someFunc;
    func();

    // member via lambda
    A obj;
    func = [&](){ obj.foo(); };
    func();

    // member via std::bind (there's also a Boost version if your compiler is ancient)
    func = std::bind(std::mem_fn(&A::foo), &obj);
    func();
}
You can also have std::function, lambdas, or std::bind using arguments and return values by spelling out the signature, e.g. std::function<result_type(param_type1, param_type2)> and then adding the forwarding params to the lambda or the placeholders (std::_1, std::_2, etc.) to std::bind.

mem_fn is not needed there, bind already handles the case of member function pointers.


    func = std::bind(&A::foo, &obj);

is sufficient. Also, let's not forget to add the necessary header include at the start...


#include <functional>

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

Thanks for the help guys, it works exactly the way I wanted.

This topic is closed to new replies.

Advertisement