2

I am new to functional library. I want to bind a static class method with the object of the class and return a void pointer to the function. I tried using std::bind but it cannot convert a class member function to free floating pointer to the function

Here is a test code that I have:

class base{
    void (*fn)();
    int m_var;
public:
    base(int var): fn(std::bind(print, this)), m_var(var){
        std::cout << "base ctor\n";
        fn(); //something like this. fn should be a void pointer to the function.
    }

    static void print(base *b){
        std::cout << b->m_var << "\n";
    }
};

int main(){
    base *b = new base(5);
    return 0;
}

This is the error I get:

error: cannot convert ‘std::_Bind_helper<false, void (&)(base*), base*>::type’ {aka ‘std::_Bind<void (*(base*))(base*)>’} to ‘void (*)()’ in initialization

I know that I cannot convert class member to a free floating function, but I need the return type of std::bind to be a void pointer as that is an input to one of the external libraries I am using. Any help/suggestion is appreciated.

sam91
  • 77
  • 7
  • 6
    If you have a functor that has state, you cannot get a plain function pointer from it. – NathanOliver Aug 07 '19 at 18:31
  • If you ever find yourself using `void*` in C++, your first thought should be "I'm *probably* doing it wrong". There are *very*, *VERY* few situations in C++ where a `void*` is the correct solution. – Jesper Juhl Aug 07 '19 at 18:33
  • 2
    @JesperJuhl, I don't see any `void*`. The OP mentioned an external API that takes a `void(*)()`. – chris Aug 07 '19 at 18:35
  • @chris I was simply reacting to "and return a void pointer".. and making a general statement about `void*` – Jesper Juhl Aug 07 '19 at 18:36
  • 1
    @st91, What is the full structure of the function you need this function pointer for? C APIs with callbacks are supposed to also have a way to pass state through. If they don't, the solutions go from ugly to hacky and the primary way to get a clean solution is for the API to be updated in a future version. – chris Aug 07 '19 at 18:37
  • @NathanOliver @chris Yes, I understand that. But is there a way to bind a static member function with the class object and get a void pointer to the function. Since external API need it to be a void pointer to the function, it becomes necessary for me to convert it. I tried using 'std::function` but it returns the `std::function type` and not `void(*)()`. – sam91 Aug 07 '19 at 18:43
  • @chris, the full structure of function is: `int getResource(void **handle, uint32_t vector)` – sam91 Aug 07 '19 at 18:46
  • 1
    @st91 A static function doesn't belong to an instance of the class, so you don't need to bind it to anything (give it state). A member function belongs to an instance, so you have to bind it to an instance (it has state). You can easily get a `void(*)(base*)` from `print` without using bind. That doesn't match `void(*)()` though, so you're still out of luck if that is what the C API wants. – NathanOliver Aug 07 '19 at 18:46
  • 1
    @st91 - I think that @NathanOliver said clearly; if you have a functor that has state, you're not going to be able to convert that to a plain old function pointer; i.e `void(*)()` – Marshall Clow Aug 07 '19 at 18:47
  • 1
    There's no clean way to do that. A function pointer is just that, 8 bytes or whatever storing an address of a function. There's no room for extra state in there on any system that I know of. The reason I ask about the API is that there's still a chance it could pass user data through by other means. For example, the Windows API passes state into the window procedure as data part of the call done on window creation. It's conceivable that there's an API out there that does user state through global state accessed from the callback. It's hard to decide without all the info. – chris Aug 07 '19 at 18:48
  • @chris, thanks. Is it possible to convert `std::function` to `void(*)()` anyway? – sam91 Aug 07 '19 at 18:59
  • No, `std::function` is a type-erased function. For example, the result of your `bind` call. It stores that functor as well as what it needs for destroying, copying, and moving the stored function. Any conversion to a function pointer that needs extra data will need a separate place for the data. If the API doesn't provide designated space for the data, you have to provide your own. There's simply no good place to put it. It's far from ideal, but the API author should have known that when designing it this way. – chris Aug 07 '19 at 19:04
  • 2
    That said, I'm intrigued why the parameter is a `void**` and how the API says this parameter is supposed to be used. – chris Aug 07 '19 at 19:07
  • @chris, thanks for your explanation. `void**` in the external api is used to register an event handler with the test operating system. – sam91 Aug 07 '19 at 19:10
  • @st91 does the external API allow you to pass any kind of user-defined value to the function you give it? If so, then use that value to pass your object's `this` pointer to a free-floating function or class `static` method. That is the most common and preferred way to use C++ non-static class methods with C-based callback APIs (there are other ways, such as using thunks). – Remy Lebeau Aug 07 '19 at 19:58

1 Answers1

3

Unfortunately you can't convert the result of std::bind to a function pointer and the reasons are quite simple. Let's try to imagine how std::bind could work. You have a function which takes some argument and a value and you want to get something callable that can be called without parameters. The only possible way to do it without generating new code in run-time is to create a functional object which stores the original function and the bound argument with overloaded operator(). Actually std::_Bind_helper is very similar to this description.

So as a result you get an object of some type which has some members. So it cannot be somehow converted to a pointer to the function which cannot store any arguments.

Dmitry Gordon
  • 2,229
  • 12
  • 20