Home > Software design >  Template that calls member function on argument
Template that calls member function on argument

Time:11-22

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)...);
  }
}

Demo

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

  • Related