Search code examples
c++classc++17pointer-to-memberstdbind

std::bind not binding to a library `typedef` ed function


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?


Solution

  • 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);
       }
    };