0

I am trying to use std::bind with a library that typedefs function.

#include <iostream>
#include <string>
#include <functional>

typedef void (*GDBusReturnFunction) (void* user_data);

class Test
{
   void reply(void* user_data)
   {
      std::cout << "Hello" << std::endl;
      return;
   }

   void test_reply()
   {
      auto reply_func = std::bind(&Test::reply, this, std::placeholders::_1);
      call(reply_func);
   }

   void call(GDBusReturnFunction func)
   {}
};

int main()
{
   Test();
}

This is the compile error I am getting

prog.cc:19:11: error: cannot convert 'std::_Bind<void (Test::*(Test*, std::_Placeholder<1>))(void*)>' to 'GDBusReturnFunction' {aka 'void (*)(void*)'}
   19 |      call(reply_func);
      |           ^~~~~~~~~~
      |           |
      |           std::_Bind<void (Test::*(Test*, std::_Placeholder<1>))(void*)>
prog.cc:22:33: note:   initializing argument 1 of 'void Test::call(GDBusReturnFunction)'
   22 |   void call(GDBusReturnFunction func)
      |             ~~~~~~~~~~~~~~~~~~~~^~~~

When I switch the method to static and do not use std::bind things work as expected.


I also tried this

     call(&reply_func);

but that returns the same error

What am I missing?

JeJo
  • 30,635
  • 6
  • 49
  • 88
cjds
  • 8,268
  • 10
  • 49
  • 84
  • 1
    Why are you expecting this to work? `call` expects a function pointer, and you are passing a function object created by `std::bind`. They are unrelated types. – super Jul 28 '20 at 04:09
  • The function pointer would have nowhere to store the bound arguments. It's a fixed size. – chris Jul 28 '20 at 04:10
  • Not an expert of the matter so it may not be a duplicate, but must be closely related to https://stackoverflow.com/questions/12662891/how-can-i-pass-a-member-function-where-a-free-function-is-expected – Tas Jul 28 '20 at 04:23
  • 1
    Is `call` supposed to represent a function from the library? If so, then it should have `void *user_data` as a parameter too. Otherwise it can't call `func` because it doesn't know what argument to pass it. Exactly what are you doing? The crux of the whole issue is that a function pointer is *not enough* to represent a function. In C++ we use things like templates+functors/`std::function` instead. In C, a function is conventionally represented by a function pointer plus "some stuff", where "some stuff" is behind a `void*`. Asking for just the function pointer is usually wrong. – HTNW Jul 28 '20 at 04:28
  • `call` is supposed to represent a function from a library unfortunately. Which does have the `void *` as a parameter – cjds Jul 28 '20 at 05:17

1 Answers1

1

The std::bind returns a unspecified type (i.e. a function object of unspecified type),

template< class F, class... Args >
/*unspecified*/ bind( F&& f, Args&&... args );
//^^^^^^^^^^^^

which can not be copied to a function pointer type.

You need to use

Nevertheless, the std::bind can be replaced with a lambda function

[this](auto user_data) { this->reply(user_data); }

A sample solution using templated Test::call function, might look like. See a demo

#include <iostream>
#include <string>

class Test
{
public:
   // optionally you could make it also template function!
   // e.g.
   // template<typename Type>
   // void reply(Type* user_data)
   void reply(void* user_data)
   {
      std::cout << "Hello" << std::endl;
   }

   void test_reply()
   {
      call([this](auto user_data) { this->reply(user_data); });
   }

   template<typename Callable>
   void call(Callable func) const
   {
      int userData = 1; // some user data
      func(&userData);
   }
};
JeJo
  • 30,635
  • 6
  • 49
  • 88
  • 1
    `GDBusReturnFunction` comes from a library. I don't think OP can just use a different type. – HTNW Jul 28 '20 at 04:21
  • `GDBusReturnFunction` and `call` both do come from a library so I cannot change them .. I am going to try a `std::function` approach. I think I understand why std::bind is different from std::function – cjds Jul 28 '20 at 05:18