Проблема заключается в том, что функция-член не является простой функцией без параметров, потому что она всегда имеет неявный параметр this
.
Если вы сталкиваетесь с устаревшим интерфейсом C, который требует простой функции обратного вызова без параметра пользовательского контекста (a void*
, который функция просто переходит на обратный вызов), у вас есть проблема.
Если у вас есть пользовательский контекст, это легко. Передайте указатель на объект в зависимости от контекста, а также использовать функцию обертки в качестве фактического обратного вызова:
typedef void (*CALLBACK)(void*);
class Filter
{
public:
static void CallbackWrapper(void* context) {
static_cast<Filter*>(context)->callback();
}
private:
void callback();
};
int main() {
Filter f;
SetCallback(&Filter::CallbackWrapper, &f);
}
Если у вас нет контекста, вот несколько вариантов:
- магазин объект в глобальную переменную и получить доступ к ней из оболочки. Это имеет очевидные недостатки использования глобальной переменной и не допускает более одного обратного вызова таким образом. Для длительных обратных вызовов это очень плохо.
- Небольшое усовершенствование, приведенное выше, заключается в использовании локальной локальной переменной потока. Это интересно для плотно обработанных обратных вызовов, например. вы вызываете функцию, которая будет сразу использовать ваш обратный вызов несколько раз, а затем вернуться. Подумайте,
qsort()
. По крайней мере, таким образом, вы не получите проблемы безопасности потоков. Все еще не вариант для длительных обратных вызовов.
- Наконец, опция, которая работает на большинстве платформ, но является большой работой, вы можете создать функцию заглушки во время выполнения, которая введет указатель на объект. Это в основном означает выделение части памяти, отключение защиты выполнения в этой памяти, если платформа использует это, и поместить там машинный код, который загружает указатель объекта и вызывает функцию на нем.
Окончательный варианта все еще имеет много недостатков: это очень зависит от платформы и может даже не работать вообще на некоторых (вы не можете отключить защиту исполнения в прошивке, AFAIK), это CPU-специфический (так как вы необходимо создать правильный код для каждого), и есть проблема управления памятью для заглушки. С другой стороны, иногда это единственное, что работает. Delphi делает такие вещи для своего окна и процедур крюка иногда, и ATL делает это тоже.
Ответ прост: вы не можете. –
Конечно, вы можете. Возможно, с некоторым синтаксисом. См. Мой ответ ниже. Он работает, но может иметь недостатки, о которых я не знаю (поэтому я призываю других прокомментировать мой ответ, пожалуйста :) – Steve