0

I'm planing to use a C lib which have a function requires to register a callback function:

int add_listen(void (*listener)(const char* param));//C code

But I met a "invalid use of const_cast" error when I'm trying to do this:

class A_Interface{
public:
A_Interface():listenerCB{[this](const char* param) {
      this->onReceived(std::string(param));
  }} {
add_listen(listenerCB.target<void(const char*)>());
};
//will be overrided by sub class
virtual void onReceived(const std::string param) = 0;
private:
std::function<void(const char*)> listenerCB;
}

Is there any other way to pass this onReceived to add_listen?

  • 2
    I don't think `target` does what you think it does. – user253751 Mar 07 '19 at 03:15
  • 2
    Unfortunately, no there isn't. You'll be surprised to learn that `onReceived` is not a function. It is a class method. There is a fundamental difference. You can't just call a class method out of thin air. You need class instance to make that happen. You could play games with `std::bind` and `std::function`, but the end result will not be a plain, garden-variety pointer that C code will understand. Unfortunately, this C library's design is not C++-compatible. The library must provide a `void *` opaque pointer that can be passed through, and synthesized into `this`, or an equivalent. – Sam Varshavchik Mar 07 '19 at 03:18
  • @SamVarshavchik Thanks to point it out, seems only static function can be passed to here, this C lib maybe is designed only for C. – Alex.Don.Scofield Mar 07 '19 at 03:38
  • @immibis Yes I think I have some misunderstanding on std::function.target, Thanks. – Alex.Don.Scofield Mar 07 '19 at 03:41
  • If you play around with static variables, probably templated ones, you can create the appropriate pointer that a static method will use internally to *then* call into your class, you can get it to work. It just doesn't look particularly pretty. – AndyG Mar 07 '19 at 03:57
  • Since `add_listen()` doesn't appear to pass a user-defined value to the callback, you could play around with [creating a thunk](https://stackoverflow.com/questions/2641489/what-is-a-thunk), which would provide the callable function pointer that `add_listen()` needs, and still be able to carry an `A_Interface*` pointer internally on which to call `onReceive()` with. This would avoid the need to use any statics at all. `std::function` doesn't provide thunking that is compatible with C, you would have to create it manually, or find a 3rd party thunking library. – Remy Lebeau Mar 07 '19 at 04:33
  • @AndyG Thanks for your advice .At the very beginning I don't want to have a static function here so I tired to use std::function to do some tricks(but it's useless). Right now I'm looking for another lib which can provide a interface with a void * to pass. – Alex.Don.Scofield Mar 07 '19 at 05:28

2 Answers2

0

As @SamVarshavchik said:

The library must provide a void * opaque pointer that can be passed through, and synthesized into this, or an equivalent

So seems there is no "pretty" way to pass this onReceived to add_listen, or create a thunk as @Remy Lebeau mentioned.

0

Wrap the native CB mechanism in a Meyer singleton:

typedef void(cb_t)(char const*);

template<
    int(*reg)(cb_t*),
    int(*ureg)(cb_t*)=nullptr
>
class wrapped_cb{
public:
    ~wrapped_cb(){
        if (!ureg)
            return;
        (*ureg)(&call_servant);
    };
    static auto signal(){ 
       static wrapped_cb cb_list;
       return cb_list.signal_prv;
    };
private:
    wrapped_cb(wrapped_cb const&)=delete;
    auto& operator=(wrapped_cb const&)=delete;

    wrapped_cb(){
       (*reg)(&call_servant);
    };

    static void call_servant(char const* s){
        signal()(s);
    };

    boost::signal2
       <decltype((call_servant))>
          signal_prv;
};

//...

wrapped_cb<&add_listen>::signal()
.connect([](char const* s){
    std::cout<<s<<std::endl;
};

wrapped_cb<&add_listen>::signal()
.connect([](char const* s){
    std::cout<<s<<" v2"<<std::endl;
};
Red.Wave
  • 2,790
  • 11
  • 17
  • @Alex.Don.Scofield you're welcome. As the description was short, I actally expected somebody complains. Have fun & let me know whenever any defect you detect in that design. – Red.Wave Mar 12 '19 at 09:35