делегаты — подпрограмма обработки прерываний в переполнении стека

Для встроенной системы реального времени я пытаюсь предоставить обработчик прерываний, который позволяет регистрировать любой указатель нестатического метода (а также, конечно, экземпляр объекта), который вызывается при возникновении прерывания.

В Си это было легко сделать, например:

void (*func)(void*) = 0; // <- method to be called goes here
void* instance;          // <- instance for this-call goes here

void InterruptHandler()
{
func(instance);
}

Афаик, это соответствует вызову this, который C ++ делает неявно при вызове нестатического метода.

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

Есть ли способ напрямую эмулировать этот вызов C ++, как в C?
Я знаю делегатов, однако мой компилятор ограничен C ++ 98, никакой библиотекой надстроек и т. Д .; и даже пользовательские облегченные реализации, например, Невозможно быстрые делегаты C ++ Сергея Рязанова дают некоторые накладные расходы, которых я бы хотел избежать, если это возможно.

1

Решение

Методы всегда содержат скрытый this параметр, обеспечивающий доступ к вызываемому объекту. Чтобы вызвать класс из обработчика прерываний, который ожидает C или C-подобное поведение вызова с соответствием 1: 1 между перечисленными параметрами и необходимыми параметрами, вы должны обеспечить это C-подобное поведение. Это означает свободные функции или статические методы без скрытых параметров.

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

Но у вас может быть статический метод или свободная функция, вызывающая метод объекта, если объект можно сделать доступным.

Дано

void (*func)(void*)

Где void * указатель на предоставленную пользователем управляющую информацию, простое решение — статический метод или свободная функция вида

void handlerCaller(void* userp)
{
ISRHandlerClass * handlerp = (ISRHandlerClass *) userp;
handlerp->isrhandler(); // tiny bit may be lost here to subclass look-up
}

А также

void isrhandler()

реализован, чтобы делать что угодно, черт возьми ISRHandlerClass или ребенок ISRHandlerClass нужно сделать.

Вы в значительной степени застряли с handlerCaller или что-то вроде этого, так что это накладные расходы, которых вы не можете избежать. Все остальное зависит от того, насколько вы хотите, чтобы интерфейс ISR был.

Простой базовый базовый класс обработчика ISR:

class ISRHandlerClass
{
public:
virtual ~ISRHandlerClass()
{
}
// pure virtual to be implemented by specialized handler
virtual void isrhandler() = 0;
};

и одинаково простой реализатор

class FooHandler: public ISRHandlerClass
{
public:
void isrhandler() //override tag if you've got 'em
{
// read Foo and store in buffer to be processed by lower priority task
}
};

Но если вы хотите отказаться от обобщения в пользу скорости, не беспокойтесь о подклассах. Вы жертвуете место для нескольких вызывающих обработчиков, если вам нужно более одного.

void FooHandlerCaller(void* userp)
{
FooHandler * handlerp = (FooHandler *) userp;
handlerp->isrhandler();
}

void BarHandlerCaller(void* userp)
{
BarHandler * handlerp = (BarHandler *) userp;
handlerp->isrhandler();
}

Или же

template <class TYPE>
void handlerCaller(void* userp)
{
TYPE * handlerp = (TYPE *) userp;
handlerp->isrhandler();
}

использование

class FooHandler
{
public:
void isrhandler()
{
// read Foo and store in buffer to be processed by lower priority task
}
};

void (*func)(void*) = handlerCaller<FooHandler>;
FooHandler handler;
void* instance = (void *)&handler;
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]