невозможно преобразовать 'int (Scheduler :: *) (int, void *)' в 'int (*) (int, void *)' для аргумента '2' в 'bool irq_InstallISR (int, int (*) (int, void*), недействительно *) ' - PullRequest
2 голосов
/ 08 октября 2019

У меня есть эта функция в заголовке irq

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

и планировщик класса

/* 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){
...
}

, и я получил эту ошибку

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

Я пробовал этов функции инициализации

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

но я также получил похожую ошибку

 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*)'

Скажите, пожалуйста, что я делаю не так?

1 Ответ

0 голосов
/ 08 октября 2019

Вы не включили объявление Scheduler :: timerrtc_isr_handler, поэтому мое первое предположение состоит в том, что вы забыли объявить этот метод как статический?

т.е. в определении класса он должен выглядеть следующим образом:

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

irq_InstallISR принимает глобальную функцию. Сообщение об ошибке говорит, что он не может преобразовать этот прототип:

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

, который является функцией-членом, в

int (*)(int, void*)

, который является нормальной функцией C (или функцией, не являющейся членом, например,статический метод).

/ edit Я предполагаю, что вы хотели что-то вроде этого шаблона:

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

Вы не выбираете междуобъявляя метод как статический или int, но выбор между статической функцией (то есть не имеющей доступа к 'this') или функцией-членом (которая требует 'this'). Рассмотрим следующее:

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

Итак, давайте сделаем еще один шаг. Давайте представим, что я написал библиотеку C-API. C не поддерживает классы C ++, поэтому обычно для взаимодействия с кодом, основанным на классах C ++, вы часто прибегаете к довольно распространенному шаблону пользовательских данных. Поэтому я постараюсь привести это к простейшему возможному примеру ....

/// 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();
  }
};

Честно говоря, я не могу упростить приведенный выше пример. Этот шаблон userData существует просто для того, чтобы вы могли вызывать функции-члены объектов C ++ из библиотеки C. Надеюсь, что вышесказанное имеет смысл, если нет, то вам, вероятно, придется прочитать статические методы и ограничения C.

...