Ссылка на нестатическую функцию-член должна вызываться при обработке обратных вызовов внутри класса - PullRequest
0 голосов
/ 28 сентября 2018

У меня есть следующий код API, предоставленный библиотекой PiGPIO.По сути, он позволяет вам установить функцию обратного вызова, когда состояние контакта было изменено.

Обычно API выглядит так:

typedef void (*gpio_callback_t)(int, int, uint32_t);
int gpioSetAlertFunc(int, gpio_callback_t)

И его можно вызывать так:

void callback_func(int pin, int NewLevel, uint32_t CurrentTicks)
{
    // Callback process
}

int main()
{
    // Setting up callback function
    gpioSetAlertFunc(10, callback_func)

    // Do stuff while callback will be called independently  
}

Теперь приведенный выше код работает отлично!


Большая проблема возникает, когда я пытаюсь обернуть этот код в класс C ++.Класс должен выглядеть следующим образом:

class Pin
{
public:
    Pin()
    {
        gpioSetAlertFunc(10, this->internal_gpio_callback) );
    }

    void internal_callback_func(int pin, int level, uint32_t tick)
    {
        cout << "New level: " << pin << " " << level;
    }
}

Проблема в том, что ссылка на эту функцию недопустима, поскольку она не является статической функцией.Чтобы вещи были более сложными, я не могу просто сделать функцию обратного вызова статической.Эта функция обратного вызова будет сильно взаимодействовать с остальными методами класса и ее внутренними переменными.

Знаете ли вы обходной путь для этого?Или, может быть, грязный хак с использованием указателей или что-то в этом роде?

Ответы [ 2 ]

0 голосов
/ 28 сентября 2018

Код библиотеки gpio не имеет понятия о ваших Pin классах, но вы не можете вызвать функцию обратного вызова вашего члена, не зная, какой объект Pin будет вызывать его.Таким образом, вам нужна некоторая (не являющаяся членом) функция, которая находит объект Pin для использования в вызове функции.

Похоже, эта информация поступает в виде параметра int pin.Таким образом, вам нужна (бесплатная) функция, которая знает обо всех ваших Pin объектах и ​​какой у них номер пин-кода, находит правильный и вызывает функцию обратного вызова:

class Pin
{
public:
    explicit Pin(int pin);
    void internal_callback_func(int level, uint32_t tick);
private:
    int _pin;
};

// Alternatively a std::array, a std::map or similar.
std::vector<Pin> allPins;

void pinCallback(int pin, int level, uint32_t tick)
{
    Pin& pinObject = allPins[pin];
    pinObject.internal_callback_func(level, tick);
    // The Pin object presumably knows its own number.
}

Pin::Pin(int pin) : _pin(pin)
{
    gpioSetAlertFunc(_pin, pinCallback);
}

void Pin::internal_callback_func(int level, uint32_t tick)
{
    cout << "New level: " << _pin << " " << level;
}

void mainOrSo()
{
    // Create some pins and store them in the vector. Each one registers the callback on construction.
    for (int i = 0; i < 16; ++i)
       allPins.emplace_back(i);
}
0 голосов
/ 28 сентября 2018

Непрерывный обратный вызов в стиле C примет аргумент void* для передачи произвольных пользовательских данных.Так как этот не делает, это ошибка в дизайне библиотеки.Поднимите проблему с авторами библиотеки.

Чтобы обойти эту проблему, вам нужно создать замыкание в качестве C-совместимой функции.Нет способа сделать это стандартным C или C ++.Хотя есть библиотеки (нестандартные и не переносимые по необходимости), которые решают эту проблему.Одна из таких библиотек - GNU libffcall , другая - libffi .Оба позволяют вам создавать замыкания, которые ведут себя как обычные функции Си.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...