I work in a memory-limited embedded environment where malloc / free new / delete is not recommended, and I'm trying to use the std :: function pattern to register callbacks. I do not have access to any STL methods in my target code, so I got into a bad situation when I had to replicate some of the STL functions. Function pointers are not an option for me because of the need to capture callers.
For example, I want to declare a class mailbox where you can register the onChange event
class Mailbox {
std::function<void(int,int)> onChange;
};
Thus, callers can register a lambda handler onChangethat can capture some variables that are relevant to the processing of the event.
Since this is part of the API, I want to give users the flexibility of Mailbox maximim to either provide a pointer to a function, or a lambda, or a functor.
I managed to find a great implementation std::function that seems to be exceptionally low and has what I need except that it includes dynamic memory.
If you look at the following code, dynamic memory is used in exactly one place, and it looks completely tied to the template, suggesting that its size should be known at compile time.
Can someone help me figure out how to reorganize this implementation so that it is completely static and removes the use of new / malloc? I am having trouble understanding why the CallableT size will not be computed at compile time.
( ). , make_unique/unique_ptr, *, .
#include <iostream>
#include <memory>
#include <cassert>
using namespace std;
template <typename T>
class naive_function;
template <typename ReturnValue, typename... Args>
class naive_function<ReturnValue(Args...)> {
public:
template <typename T>
naive_function& operator=(T t) {
callable_ = std::make_unique<CallableT<T>>(t);
return *this;
}
ReturnValue operator()(Args... args) const {
assert(callable_);
return callable_->Invoke(args...);
}
private:
class ICallable {
public:
virtual ~ICallable() = default;
virtual ReturnValue Invoke(Args...) = 0;
};
template <typename T>
class CallableT : public ICallable {
public:
CallableT(const T& t)
: t_(t) {
}
~CallableT() override = default;
ReturnValue Invoke(Args... args) override {
return t_(args...);
}
private:
T t_;
};
std::unique_ptr<ICallable> callable_;
};
void func() {
cout << "func" << endl;
}
struct functor {
void operator()() {
cout << "functor" << endl;
}
};
int main() {
naive_function<void()> f;
f = func;
f();
f = functor();
f();
f = []() { cout << "lambda" << endl; };
f();
}
: STL