Итак, у меня следующая ситуация:
Я пишу для онлайн-компилятора mbed на микроконтроллере с малым объемом памяти.
Производительность в реальном времени очень важна, я хочу, чтобы это занимало меньше микросекунды. 10 микросекунд будут терпимы.
Я использую их библиотеку тайм-аутов, которая предоставляет API для вызова ISR после указанного времени, но требует, чтобы ISR была функцией void / void. (включая функцию-член.
void TimeoutCallback(void) { do stuff that I want to do on timeout.} // ISR
Timeout to;
to.attach_us(&TimeoutCallback, 750) // Call TimeoutCallback in 750 us.
Я создал вектор объектов Timeout, которые все устанавливаются одновременно для одной и той же функции с разным количеством времени. Я хочу как-то перейти в TimeoutCallback который Объект таймаута вызвал это.
Сначала я задумался о том, чтобы перегрузить класс Timeout, чтобы он мог принимать указатели на функции int (int) и принимать число в перегруженной функции присоединения, которая передается указателю на указанную функцию. Однако я не уверен, является ли это на самом деле практичным, учитывая беспорядочное (и зависящее от устройства) наследование класса Timeout.
Теперь мне интересно, есть ли способ программно создать функцию void / void, которая оборачивает функцию void / int и включает переменную ссылку int, которая передается в обернутую функцию.
Поскольку ваша библиотека может вызывать функции-члены, вы можете создать адаптер …
template <typename Func, Func func>
struct Adapter
{
Adapter(int n) : n_(n) { }
void f() { func(n_); }
int n_;
};
Чтобы использовать это:
Adapter<void(*)(int), My_Function_Expecting_An_Int> adapter(the_int);
to.attach_us(&adapter, &decltype(adapter)::f, timeout_us);
Убедитесь, что adapter
Время жизни длится до обратного вызова ….
Чтобы вызвать функцию-член:
#include <iostream>
#include <string>
#include <vector>
struct MyObj
{
void f(int n) { std::cout <<"hi " << n << "\n"; }
};
template <typename Class, typename PFunc>
struct Adapter
{
Adapter(Class& object, PFunc pFunc, int n) : object_(object), pFunc_(pFunc), n_(n) { }
void f() { (object_.*pFunc_)(n_); }
Class& object_;
PFunc pFunc_;
int n_;
};
int main()
{
MyObj myObj;
Adapter<MyObj, void(MyObj::*)(int)> adapter(myObj, &MyObj::f, 43);
adapter.f();
}
Хотя решение Тони Ди уместно, если вы используете mbed Ticker
класс, есть альтернативный метод, использующий mbed RtosTimer
.
RtosTimer
Конструктор занимает void*
аргумент, который передается обработчику по таймауту. Обработчик имеет подпись:
void handler(void const* n)
куда n
является аргументом указателя, передаваемым конструктору и может использоваться для идентификации определенного времени ожидания.
В отличие от Ticker
где функция тайм-аута выполняется в контексте прерывания, для RtosTimer
обработчик работает как поток, что дает большую гибкость, но потенциально большую задержку.