0

I'm in a situation like this:

class Callee {
public:
  void request();
};

class Caller {
  void call() {
    Callee{}.request();
  }
  void invoke1(); // the implementation doesn't matter
  void invoke2(); // the implementation doesn't matter
  // more invoke()s
};

I want Callee::request() to request invocation of one of the Caller::invoke() member functions depending on the context which can be computed either in Callee::request() or in Caller::call():

void Callee::request() {
  // do stuff
  switch (context) {
    // request one of the invoke()s to be run immediately
  }
  // do more stuff
}

Which solutions would be elegant? I don't want (from most to least important):

  • Callee to know the definition of Caller;
  • use templates;
  • Callee to know the declaration of Caller;
  • Caller to choose an invoke() on its own;

It's OK if Callee::request() receives some arguments from the Caller.

passing_through
  • 1,778
  • 12
  • 24
  • Pass the context to `request` – Thomas Sablik Mar 31 '20 at 12:12
  • 1
    If all of the invoke functions have same signature, you can pass appropriate `std::function` object to the `Callee::request`. – Ashwani Mar 31 '20 at 12:12
  • You have conflicting requirements: if Callee isn't aware of Caller methods, how can it *choose* which one to call? Please clarify, do you want the calling for example to happen based on just index number or what? Or did I misunderstand the requirement for Callee to be able to choose? – hyde Mar 31 '20 at 12:13
  • 1
    There's no nice way to satisfy all your requirements. If you don't want to use templates, then you could use an abstract base-class for `Caller` that the `Callee` class needs to know about. Templates and passing the `Caller` objects to the `request` function seems like the simplest solution to me. – Some programmer dude Mar 31 '20 at 12:13
  • @Ashwani how? As I know, member functions require an object of the class to be called; doesn't it mean I can't just pass a `std::function`? – passing_through Mar 31 '20 at 12:26
  • @hyde actually, I was hoping for a solution somehow connected with passing function pointers to the callee. – passing_through Mar 31 '20 at 12:29
  • 1
    Ashwani is correct. You can store `[this](){this->invoke1();}` in a `std::function`. That's a lambda, if you don't recognize the form. It captures `this`. – MSalters Mar 31 '20 at 12:57
  • @passing_through Of course, doing that is easy (passing `std::function` is easiest), if callee doesn't need to choose. But your requirement conflicts with this simple solution. You could edit the question to define what you mean by callee beimg able to choose the caller function. – hyde Mar 31 '20 at 15:09

1 Answers1

0

There is a number of ways you can achieve this.

  • The most straightforward is to have Callee::request() return an enum value, which the Caller then does a switch on and invokes an appropriate function. This means that caller and callee will have to both know this enum.

  • Another way which is also in straightforward territory, though slightly more convoluted, is to pass a single function from the caller to the callee, which accepts that enum value as a parameter, so that by invoking this function the callee can indicate to the caller what it wants done. Again the caller can switch on that value and invoke either invoke1() or invoke2() or what have you.

  • Another way is to define an interface, (a class consisting of only pure virtual methods,) which contains invoke1() and invoke2() have the caller implement that interface, and pass that interface of itself to the callee, so that the callee can decide which function to call. In this case, caller and callee will need to both have knowledge of this new interface.

  • Another way is to pass the callee two pointers to functions, so that the callee can decide which one to call. This way the callee does not need to know anything, but it does not scale very well, because what if you have 50 different functions?

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142