I've written an object that stores a std::function<void(void*)>
, which is passed in as an argument to the constructor. The object will later call back this std::function at some point in the future. This is implemented and working great.
In each class which uses this object, they call the constructor in the initialization list like so:
mCallbackObj(std::bind(&MyClass::MyFunc, this, _1))
However, I've found that every class which contains this object as a member is increasing my codespace by ~2K. With potentially hundreds of places where this object will be used, and limited codespace options (this is an embedded product), a 2k hit per use isn't acceptable.
One interesting observation is that if a class has a second object:
mCallbackObj2(std::bind(&MyClass::MyOtherFunc, this, _1))
this only increases codespace by some ~150 bytes - very acceptable! It is only when the object is used in different classes that I see the 2K hit. Putting the classes all in one .cpp file doesn't help - still a 2k hit per class that contains this object.
I've played around with using extern template class std::function<void(void*)>;
, but this had no impact on ROM size.
I am using gcc 4.8. I'd love to use std::function
and std::bind
, but am about to give up and switch to class method pointers. They wouldn't be nearly as clean, but hopefully more ROM efficient.
Before I give up on this, are there any other options to help reduce my template codespace bloat?
I dug into this a bit more and watched @John's video on std::function
. In the video, STL recommends using lambdas over std::bind
for a few reasons.
I tried converting the code to use a Lambda, which is exactly what @Igor Tandetnik recommended above. It is significantly better.
mCallbackObj(std::bind(&MyClass::MyFunc, this, _1))
Takes an additional 2,888 bytes of codespace. Instead using
mCallbackObj([this](void *info){MyFunc(info);})
Only takes an additional 812 bytes! This is significantly better, and good enough for my use-case. For C++ programmers unfamiliar with the syntax of std::bind, the lambda solution is also easier to read.
Update -
After bumping to GCC 6.0 and tweaking our compiler flags (we weren't always passing in -O2 previously), I've retested this.
Lambda: 216 bytes
std::bind: 221 bytes
function pointer: 228 bytes
All 3 are now much more reasonable. We are mostly using lambdas, as they are the easiest to read once developers are familiar with the syntax.