I have some code that creates several listeners. Thus I was thinking about adding a template that calls the notify on different types of listeners. However I am not sure how to call the member function (which all have different arguments) in a template. I am using C 17.
template <class T>
void notifyListeners(std::vector<T*> listeners, std::function<???> memfunc) {
// perhaps add a compile time check to see if memfunc exists
for (auto& listener : listeners) {
listener->memfunc();
}
}
For example I have two classes of listeners :
class IFooListener {
void Foo(int, double, std::string);
}
class IBarListener {
void Bar(std::string, std::string)
}
std::vector<IFooListeners*> fooListeners;
std::vector<IBarListeners*> barListeners;
I would like to be able to do something like this:
notifyListeners(fooListeners, &IFooListener::Foo, 1, 2.0, "Bla");
notifyListeners(barListeners, &IBarListener::Bar, "one", "two");
How can this be done?
CodePudding user response:
template <class T, typename F, typename... Args>
void notifyListeners(std::vector<T*> listeners, F f, Args&&... args) {
for (auto& listener : listeners) {
(listener->*f)(std::forward<Args>(args)...);
}
}
CodePudding user response:
Not sure if I understand problem correctly. Here is my first approach using C 17:
template <typename T>
class Notifier {
public:
void addObserver(T observer)
{
mObservers.emplace_back(observer);
}
template<auto f, typename...Ts>
void notify(Ts&&...args) const
{
for(auto& p : mObservers)
{
notifyOne<f>(p, std::forward<Ts>(args)...);
}
}
private:
template<auto f, typename...Ts>
static void notifyOne(T p, Ts&&...args)
{
(p->*f)(std::forward<Ts>(args)...);
}
private:
std::vector<T> mObservers;
};
Here as some tests proving it works.
Disclaimer: I used perfect forwarding, but in case same argument may be used multiple times this is not best choice. I think some protection form moving argument values should be added.
Here is C 11 version with function pointer pass as function argument.
Edit: Got another improvement. Now this template is able to handle std::weak_ptr
: demo