简体   繁体   中英

cannot convert 'int (Scheduler::*)(int, void*)' to 'int (*)(int, void*)' for argument '2' to 'bool irq_InstallISR(int, int (*)(int, void*), void*)'

I have this function in irq header

/* irq.h */
bool irq_InstallISR(int irq, int (*isr)(int, void*), void* isr_data);

and a class Scheduler

/* Scheduler.cpp */
using namespace x86Duino;
void Scheduler::init(){
...
irq_InstallISR(RTCIRQ, &Scheduler::timerrtc_isr_handler, isrname_rtc);
...
}

int Scheduler::timerrtc_isr_handler(int irq, void* data){
...
}

and I got this error

error: cannot convert 'int (x86Duino::Scheduler::*)(int, void*)' to 'int (*)(int, void*)' for argument '2' to 'bool irq_InstallISR(int, int (*)(int, void*), void*)'

I have tried this in init function

using namespace std::placeholders;
irq_InstallISR(RTCIRQ, std::bind(&Scheduler::timerrtc_isr_handler, this, _1, _2), isrname_rtc);

but I also got a similar error

 error: cannot convert 'std::_Bind_helper<false, int (x86Duino::Scheduler::*)(int, void*), x86Duino::Scheduler*, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type {aka std::_Bind<int (x86Duino::Scheduler::*(x86Duino::Scheduler*, std::_Placeholder<1>, std::_Placeholder<2>))(int, void*)>}' to 'int (*)(int, void*)' for argument '2' to 'bool irq_InstallISR(int, int (*)(int, void*), void*)'

Please tell me what I'm doing wrong?

You haven't included the declaration of Scheduler::timerrtc_isr_handler, so my first guess would be that you forgot to declare that method as static?

ie In the class definition, it should look like:

class Scheduler
{
  static int timerrtc_isr_handler(int irq, void* data);
};

The irq_InstallISR takes a global function. The error message says it cannot convert this prototype:

int (Scheduler::*)(int, void*)

Which is a member function, to

int (*)(int, void*)

Which is a normal C function (or non-member function, eg a static method).

/edit I'm guessing you wanted something along the lines of this pattern:

class Scheduler
{
public:
  Scheduler()
  {
    irq_InstallISR(RTCIRQ, timerrtc_isr_handler, this);
  }
  ~Scheduler()
  {
    // probably want to uninstall the callback here!
  }

  int isr_handler(int irq)
  {
    /// do you handling here
  }
private:
  static int timerrtc_isr_handler(int irq, void* data)
  {
    // cast user data to correct class type
    Scheduler* sch = (Scheduler*)data;
    assert(sch); // just in case we get null for some reason?

    // thunk call to member function
    return sch->isr_handler(irq);
  }
};

/edit 2

You aren't choosing between declaring the method as static or int, but the choice is between a static function (ie does not have access to 'this'), or a member function (which requires 'this'). Consider the following:

struct Foo
{
  void func1() { std::cout << "func1\n"; }
  static void func2() { std::cout << "func2\n"; }
};

void bar()
{
  // call the static method - does not require an object!
  Foo::func2(); 

  // to call func1, we ALWAYS need an object... 
  Foo obj;
  obj.func1(); 
}

So let's take it another step. Let's imagine I've written a C-API library. C does not have support for C++ classes, so typically in order to inter-operate with C++ class based code, you often resort to a fairly common user data pattern. So I'll try to strip this down to the simplest possible example....

/// MyLib.h


// I want to call this method, and it will inturn call any 
// callback functions registered with the system. 
void callMyRegisteredFunction();

// the type of function I want to call in the previous method
// The C++ way of doing this is to say :
// 
//   someObject->func();
//
// However in C, without classes, the way you'd call it would be:
//
//   func(someObject); 
// 
// so the second pointer here is the object to call it on. 
typedef void (CallbackFunc*)(void*);

// register a callback function, and an associated user-defined object
void registerFunc(CallbackFunc funcPtr, void* userData);

// reset the internal callback
void unregisterFunc();

/// MyLib.cpp
#include "MyLib.h"

// the currently registered callback function
CallbackFunc g_func = NULL;

// the 'object' it is registered against. From 'C' we don't know that 
// what type of object this is, we just know it's address. 
void* g_userData = NULL;

void registerFunc(CallbackFunc funcPtr, void* userData)
{
  g_func = funcPtr;
  g_userData = userData;
}
void unregisterFunc()
{
  g_func = NULL;
  g_userData = NULL;
}

void callMyRegisteredFunction()
{
  // don't call invalid method
  if(!g_func) return;

  // call the function, and pass it the userData pointer
  // This code does NOT know about C++ code, or the class 
  // type that you registered. 
  g_func(g_userData);
}
class MyCallbackObject
{
public:
  MyCallbackObject()
  {
    registerFunc(C_callback, this); //< NOTE: !!this!!
  }

  ~MyCallbackObject()
  {
    unregisterFunc();
  }

  // everything else prior exists PURELY to be able to call this C++ 
  // class method, from C code, that has absolutely NO idea about how 
  // your class is defined. 
  // NOTE: I'm making this method virtual so that instead of duplicating
  // the boiler plate code everywhere, you can just inherit from this 
  // class, and override the doThing method. 
  virtual void doThing()
  {
    /// do you handling here
  }
private:
  static void C_callback(void* userData)
  {
    // cast user data to correct class type
    MyCallbackObject* obj = (MyCallbackObject*)userData;

    // now call the method
    obj->doThing();
  }
};

Honestly, I can't make the above example any simpler. This userData pattern exists simply so that you can call member functions of C++ objects from a C library. Hopefully the above makes sense, if not you'll probably need to read up on static methods, and the limitations of C.

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