I'm quite new to the STL.
Does this make sense? Is there a better way of removing the listeners instead of using shared_ptr while keeping the code short and simple? Is there something in the STL to replace this?
Class:
template<class ... Arguments>
class Callback
{
using Function = std::function<void(Arguments ...)>;
using FunctionPtr = std::shared_ptr<Function>;
using Functions = std::vector<FunctionPtr>;
public:
FunctionPtr addListener(Function f) {
FunctionPtr fp = std::make_shared<Function>(f);
_functions.push_back(fp);
return fp;
}
void removeListener(FunctionPtr fp){
_functions.erase(std::find(_functions.begin(), _functions.end(), fp));
}
void operator()(Arguments ... args) const{
for (auto & f : _functions)
f.get()->operator()( args ... );
}
private:
Functions _functions;
};
Use case:
int main()
{
Callback<int> callback;
callback.addListener([](int i){
std::cout << "Listener 1 -> Input is " << i << std::endl;
});
auto id = callback.addListener([](int i){
std::cout << "Listener 2 -> Input is " << i << std::endl;
});
callback.addListener([](int i){
std::cout << "Listener 3 -> Input is " << i << std::endl;
});
callback.removeListener(id);
callback(71);
}
Output is:
Listener 1 -> Input is 71
Listener 3 -> Input is 71
Addendum One limitation of this approach is that you can't remove or add listeners inside the callback functions since it would break the iteration. What I found is that this limitation is especially annoying when you want something to only trigger once and then be removed. The easiest solution I found is to simply have a separate list of callbacks that are called once and then removed automatically after the iteration. Another easy, more generic solution is to copy the listeners container before triggering the callbacks with the obvious performance cost.