简体   繁体   中英

c++ bind member function (callback)

im trying to bind a member function to a function pointer that is then registered. there is an error i cannot solve:

Includes :

<functional> and all gcc stdXX (stdio.h, stdlib.h,...)

Callback type to register in atl::hal::lib::uart

void (*f_callback_t)(void* /*data*/, callback_t /*type*/);

My object in atl::hal::obj::uart

class CLI
{
public:

void init() 
{
    atl::hal::lib::uart::f_callback_t pevt;

    // ERROR !!! <----------------------------------------------
    pevt = std::bind(
        &atl::hal::obj::uart::obj::_eventhandler,
        this,
        std::placeholders::_1,
        std::placeholders::_2);
}

private:
  void _eventhandler(
      void* data,
      atl::hal::lib::uart::callback_t type)
  {
    M_ASSERT_BOOL(false);
  }
}

ERROR

cannot convert 'std::_Bind_helper<false, void (atl::hal::obj::uart::obj::*)(void*, atl::hal::lib::uart::callback_t), atl::hal::obj::uart::obj*, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type {aka std::_Bind<std::_Mem_fn<void (atl::hal::obj::uart::obj::*)(void*, atl::hal::lib::uart::callback_t)>(atl::hal::obj::uart::obj*, std::_Placeholder<1>, std::_Placeholder<2>)>}' to 'atl::hal::lib::uart::f_callback_t {aka void (*)(void*, atl::hal::lib::uart::callback_t)}' in assignment

You can't store bind results in a simple function pointer type.

You can check whether defined type is a bind_expression (that is, it stores some kind of bind) by using the following type trait:

std::is_bind_expression<bind_type>::value

SHORT SOLUTION:

Just use auto keyword and let the compiler deduce the bind expression type for you.


LONG SOLUTION

Manually define correct type.

For simplified scenario (because you didn't show atl::hal::obj::uart::obj code), to store a bind to a CLI::_eventhandler , the final code will look like this:

class CLI
{
public:
    using bind_type = decltype(std::bind(std::declval<void (CLI::*)()>(), std::declval<CLI*>(), std::declval<const std::_Ph<1>&>(), std::declval<const std::_Ph<2>&>()));

void init()
    {   
        bind_type  pevt1 = std::bind(
            &CLI::_eventhandler,
            this,
            std::placeholders::_1,
            std::placeholders::_2);
    }

private:
    void _eventhandler()
    { }
};

Details:

decltype(std::bind(std::declval<void (CLI::*)()>(), std::declval<CLI*>(), std::declval<const std::_Ph<1>&>(), std::declval<const std::_Ph<2>&>()));
  • decltype(...) : Returns type declaration for an expresion inside the brackets.
  • std::bind : We want the resulting type of std::bind so we must include the call here.
  • std::declval<void (CLI::*)()>() :
    • std::declval<T>() : Simply returns a reference to type T, so that we don't need a dummy object or expression to use inside decltype.
    • std::declval<void (CLI::*)()>() : returns reference to CLI member function pointer generated by declval, so decltype can deduce it type.
  • std::declval<CLI*>() : Same as above but returns pointer to CLI* (the *this pointer argument).
  • std::declval<const std::_Ph<2>&>() : Placeholder type, I can't really elaborate on that because I extracted it's name from error message. Probably there is a nicer and safer way to define this, maybe someone smarter can help :)
  • std::declval<const std::_Ph<2>&>() : Second placeholder.

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