Search code examples
c++switch-statementrefactoring

Refactoring switch statement with template function using the type


I am trying to refactor several switch-case statements littered across the code base that have the following structure:

enum Model {
  a = 1, b = 2, c = 3, d = 4, e = 5
};

function computeVal(Model m, int param1, int param2, int param3){
  Eigen::MatrixXd val, val2;

  swtich(m) {
    case Model::a:
      val = someFunc<classA>(param1, param2, param3);
      val2 = someFunc2<classA>(param1, param2, param3);
      // some more common logic
    case Model::b:
      val = someFunc<classB>(param1, param2, param3);
      val2 = someFunc2<classB>(param1, param2, param3);
      // some more common logic
    case Model::c:
      val = someFunc<classC>(param1, param2, param3);
      val2 = someFunc2<classC>(param1, param2, param3);
      // some more common logic
    case Model::d:
      val = someFunc<classD>(param1, param2, param3);
      val2 = someFunc2<classD>(param1, param2, param3);
      // some more common logic
    default:
      val = someFunc<classE>(param1, param2, param3);
      val2 = someFunc2<classE>(param1, param2, param3);
      // some more common logic
  }
}

classA, classB, classC, classD, and classE all inherit from a base class (classBase).

someFunc and someFunc2 initialize the class in the template and use it.

What is a potential way to refactor this? Or should I even be refactoring this?

I was looking at a hashmap / unordered map which would map the Model enum type to the class but I am running into errors.

e.g.:

function computeVal(Model m, int param1, int param2, int param3) {
  std::unordered_map<int, classBase*> modelMap = {
    {Model::a, classA},
    {Model::b, classB},
    {Model::c, classC}, 
    ...
  };
  
  val = someFunc<modelMap[m]>(param1, param2, param3);
  val2 = someFunc2<modelMap[m]>(param1, param2, param3);
  // some common logic
}

I get the following error: expected primary-expression before '}' token. Which makes sense since it expects a reference to an initialized class when initializing the map. Thats not what I want here though.

Any ideas on how to clean this up?


Solution

  • After talking with a co-worker and doing some more research - the consensus was:

    1. The switch statement itself isn't refactorable
    2. The logic inside each case can be refactored into a function as it is exactly the same

    e.g.

    template<class LL>
    function commonLogic(int param1, int param2, int param3){
      LL someClass();
      val = someFunc<someClass>(&someClass, param1, param2, param3);
      val2 = someFunc2<someClass>(&someClass, param1, param2, param3);
      // some more common logic
      
    }
    
    function computeVal(Model m, int param1, int param2, int param3){
      Eigen::MatrixXd val, val2;
    
      swtich(m) {
        case Model::a:
          computeVal<classA>(param1, param2, param3);
        case Model::b:
          computeVal<classB>(param1, param2, param3);
        case Model::c:
          computeVal<classC>(param1, param2, param3);
        case Model::d:
          computeVal<classD>(param1, param2, param3);
        default:
          computeVal<classE>(param1, param2, param3);
      }
    }
    

    This follows the DRY principle but I can see why this would just be pre-mature refactoring.