Для встроенной системы реального времени я пытаюсь предоставить обработчик прерываний, который позволяет регистрировать любой указатель нестатического метода (а также, конечно, экземпляр объекта), который вызывается при возникновении прерывания.
В Си это было легко сделать, например:
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 ++ Сергея Рязанова дают некоторые накладные расходы, которых я бы хотел избежать, если это возможно.
Методы всегда содержат скрытый 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;
Других решений пока нет …