mardi 2 juin 2020

Double Dispatch in C++

I have the need for the following type of dispatch function. In my application, what I really have is a pointer to a state base class (foo) as well as a pointer to a measurement base class (bar). Based on what derived instance is passed to the dispatch2 function, I need to produce an estimated measurement given the state. For instance, the derived state class can be position and the derived measurement class can be ToF (time of flight). The handler would then take the state information from f (e.g. emitter location) as well as the collector information from b (e.g. sensor positions), and calculate the expect ToF given those. This is then returned and can be compared against the actual measurement value (b).

string dispatch2(foo* f, bar* b) {
  if      ( dynamic_cast<Foo>(f) )  return foo1(f,b);
  else if ( dynamic_cast<FOo>(f) )  return foo2(f,b);
  else if ( dynamic_cast<FOO>(f) )  return foo3(f,b);
  throw std::runtime_error("dispatch for f not defined");
}

string foo1(foo* f, bar* b) {
  if      ( dynamic_cast<Bar>(b) )  return foo1bar1handler(f,b);
  else if ( dynamic_cast<BAR>(b) )  return foo1bar2handler(f,b);
  throw std::runtime_error("foo1: dispatch for b not defined");
}

string foo2(foo* f, bar* b) {
  if      ( dynamic_cast<Bar>(b) )  return foo2bar1handler(f,b);
  else if ( dynamic_cast<BAR>(b) )  return foo2bar2handler(f,b);
  throw std::runtime_error("foo2: dispatch for b not defined");
}

string foo3(foo* f, bar* b) {
  if      ( dynamic_cast<Bar>(b) )  return foo3bar1handler(f,b);
  else if ( dynamic_cast<BAR>(b) )  return foo3bar2handler(f,b);
  throw std::runtime_error("foo3: dispatch for b not defined");
}

string foo1bar1handler(foo* f, bar* b) {return "FooBar";}
string foo2bar2handler(foo* f, bar* b) {return "FooBAR";}
string foo3bar1handler(foo* f, bar* b) {return "FOoBar";}
string foo2bar2handler(foo* f, bar* b) {return "FOoBAR";}
string foo2bar1handler(foo* f, bar* b) {return "FOOBar";}
string foo2bar2handler(foo* f, bar* b) {return "FOOBAR";}

Obviously, there is no way to get around the need for defining the end methods for each combination I'd like to explicitly handle. But, I'm looking for alternative ways to implement this. Ideally, some pattern that would allow users to register each handler explicitly, and any combination that isn't handled could throw a runtime exception. Any suggestions would be appreciated. Thanks

Aucun commentaire:

Enregistrer un commentaire