lundi 27 décembre 2021

Generic function to call recursive templated function with different template parameters

I have a templated function hierarchy which works like this:

template <typename T>
SomeClass<T> Primary(SomeInputClass& input) {
  vector<SomeClass<T>> individual_results;
  for (auto& next_states : input.GetNextStates()) {
    //
    // change input's internal state here, then call:
    //
    if (/* needs recursion based on some condition in input */ ) 
      individual_results.push_back(SwitcherCaller<T>(input)); 
    else 
      // some base case operations with individual_results
  }
  
  SomeClass<T> aggregated_results = AggregateIndividualResults<T>(individual_results);
  return aggregated_results;
}

template <typename T>
SomeClass<T> SwitcherCaller(SomeInputClass& input) {
  string type = input.GetTypeFromInternalState();

  if (type == "ClassA") return Switcher<T, ClassA>(input);
  else if (type == "ClassB") return Switcher<T, ClassB>(input);
  else if (type == "ClassC") return Switcher<T, ClassC>(input);
}

template <typename T, typename C>
SomeClass<T> Switcher(SomeInputClas& input) {
  SomeClass<C> child_results = Primary<C>(input);
  SomeClass<T> parent_results = CreateParentResultsFromChild<T, C>(input, child_results);
  return parent_results;
}

The above code captures what I want to do generically in a data processing pipeline. This pipeline is generic, so it can be called with different kinds of templates by different callers.

The callers need to do the following:

  1. Make the first call to Primary with a root template, with an instance of SomeInputClass with its internal state configured as required.
  2. Implement SwitcherCaller for all possible child classes that can be reached as defined by the internal states.

For example, assume there are two callers. Caller 1 does the following:

void PrimaryCallerOne() {
  SomeInputClass input = CreateInputForCallerOne();
  SomeClass<RootClassOne> results = Primary<RootClassOne>(input);
}

template <typename T>
SomeClass<T> SwitcherCaller(SomeInputClass& input) {
  string type = input.GetTypeFromInternalState();

  if (type == "ClassOneA") return Switcher<T, ClassOneA>(input);
  else if (type == "ClassOneB") return Switcher<T, ClassOneB>(input);
  else if (type == "ClassOneC") return Switcher<T, ClassOneC>(input);
}

And Caller 2 does this:

void PrimaryCallerTwo() {
  SomeInputClass input = CreateInputForCallerTwo();
  SomeClass<RootClassTwo> results = Primary<RootClassTwo>(input);
}

template <typename T>
SomeClass<T> SwitcherCaller(SomeInputClass& input) {
  string type = input.GetTypeFromInternalState();

  if (type == "ClassTwoA") return Switcher<T, ClassTwoA>(input);
  else if (type == "ClassTwoB") return Switcher<T, ClassTwoB>(input);
}

Calling Primary is easy. My problem is, how do I design this to implement SwitcherCaller() elegantly? One way is to put all these functions in a class, make SwitcherCaller() virtual, and have each caller implement it.

Is there any other way without classes? Maybe using functors?

Aucun commentaire:

Enregistrer un commentaire