简体   繁体   中英

Dynamically creating a static function that calls a member method function in C++

I'm using an API call from a library that takes a void function(void) pointer as a parameter

 static inline void attach(void(*userFunc)(void));

And I have a class Button with a member method void buttonClicked() .

What I want is to basically make a static function dynamically at runtime that will be like:

void functionForThisSpecificObject(){
    theSpecificObject.buttonClicked();
}

I tried with a lambda like this:

 Button* self = this;
 attach([self](){self->buttonClicked();});

But then it can't be used as a static function pointer because it is a capturing lambda...

I don't want to create a static function for every object that I will be using manually, so how can this be done dynamically?

Thank you in advance for any help.

What I want is to basically make a static function dynamically at runtime

There is no way to "make" functions dynamically at runtime in C++.

What you maybe could do is meta-programming: Write a program that generates the C++ source that defines the functions that you want. Due to lacking reflection features, this generation cannot be done within the language.

I don't want to create a static function for every object

You could potentially avoid this by using a variable in static storage:

extern Button* theVariableObject; // don't forget do define

void functionForThisSpecificObject(){
    theVariableObject->buttonClicked();
}

// somewhere
theVariableObject = &theSpecificObject1; // function will now use this object

theVariableObject = &theSpecificObject2; // and now another

Yes, global state is bad, but the API that you describe doesn't allow access to any other state so if you need state, then this is it.

Probably the ideal solution is to improve the library so that you aren't limited to only global state.


PS

Button* self = this; [self](){self->buttonClicked();}

This could be simplified to:

[this](){buttonClicked();}

A capturing lambda won't work, as it is not convertible to a C-style function pointer. Only a non-capturing lambda can be converted.

Since the library in question does not allow you to pass a user-defined value to the callback function, there are basically only 2 ways to solve this:

  • store the object pointer in a global variable, and then use a standalone callback function to act on that variable.

     Button *btn; void clickTheButton() { btn->buttonClicked(); } ... { btn = this; attach(&clickTheButton); }

    Obviously, this will only work if you have 1 Button .

  • use a thunk for the callback.

    Dynamically allocate a block of memory at runtime, store some CPU instructions in it to CALL a function in your app's code, and store the value of the Button* pointer in the appropriate bytes so that value gets passed to that function. Grant the memory block execution rights, and pass it to the library.

    When the library calls the thunk, its instructions will be executed like a normal function, and they can then call into your normal code passing it the correct Button* pointer to act on.

    For instance, the thunk could CALL the Button::buttonClicked() method directly, passing the stored Button* in the this parameter, according to the calling convention of buttonClicked .

    This is a very advanced, platform/CPU-specific technique, but it is a powerful one. I would not suggest trying to code this yourself, unless you have experience in assembly coding. Otherwise, use a pre-existing library that implements this for you. There is nothing provided natively in C++ to handle this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM