I tried to make a callback type for embedded, I know std::function and lambda but I know that there is some dynamic memory allocation that I want to avoid, I came to this implementation:
#pragma once
namespace interfaces
{
template <class returnType, class ... parameterType>
class ICallable
{
public:
virtual returnType execute(parameterType ... args) = 0;
};
}
static callback :
#pragma once
#include "ICallable.hpp"
template <class ReturnType, class ... ParameterType>
class StaticCallback : public interfaces::ICallable <ReturnType,ParameterType...>
{
public:
typedef ReturnType (*CallbackFunction)(ParameterType ...);
constexpr StaticCallback(CallbackFunction function) : m_function(function)
{
}
virtual ReturnType execute(ParameterType ... args) override final
{
return m_function(args...);
}
private:
CallbackFunction m_function;
};
and callback with an object
#pragma once
#include "volund/interfaces/system/ICallable.hpp"
template <class objectType,class returnType,class ... parameterType>
class ObjectCallback : public interfaces::ICallable<returnType, parameterType ...>
{
public:
typedef returnType (objectType::*Callbackfunction)(parameterType ... args);
constexpr ObjectCallback(objectType& self, Callbackfunction function) : m_object(&self), m_functionToCall(function)
{
}
constexpr ObjectCallback(objectType *self, Callbackfunction function) : m_object(self), m_functionToCall(function)
{
}
virtual returnType execute(parameterType ... params) override final
{
return (*m_object.*m_functionToCall)(params...);
}
private:
objectType* m_object;
Callbackfunction m_functionToCall;
};
I'm not sure about the reason of dynamic allocation in std::function, so I'm wondering if there is no pitfall I didn't see in my solution.
If someone have any tips or advice that would be great =)
EDIT :
This is how i use it, typically from a driver that trigger an interrupt and user code register a callback to define some code to be executed on interrupt :
class driver
{
public:
void setCallback(ICallable* callback)
{
m_callback = callback;
}
driver& get()
{
return s_self;
}
private:
static s_self;
Icallable* m_callback;
static void interrupt()
{
s_self.m_callback->execute();
}
}
class user
{
public:
void task()
{
driver::get().setCallback(&m_callFromDriver);
while(true)
{
//do something
}
}
private:
ObjectCallback m_callFromDriver = ObjectCallback(this, &user::onEvent);
void onEvent()
{
//do something
}
}