Search code examples
c++classtemplatessubclass

Can I use C++ templates to implement two classes which only differ by one field type?


I am trying to implement a Controller class for two systems. Each Controller uses a Solver class instance.

I already have two Solver class implementations:

class AbstractSolver { virtual void func() = 0; };
class System1Solver : AbstractSolver { void func() override; };
class System2Solver : AbstractSolver { void func() override; };

The Controller implementation is the same for both Solver types. I could implement both Controller classes like...

class System1Controller { 
  public:
    System1Controller(System1Solver solver);
    System1Solver solver;
    void func() { solver.func(); };
};

class System2Controller { 
  public:
    System2Controller(System2Solver solver);
    System2Solver solver;
    void func() { solver.func(); };
};

I'd like to not copy and paste the same code. Both System?Controller implementations are identical, except for the type of solver. Can I instead use templates somehow to achieve code re-use?

template <class SolverClass>
class Controller {
  public:
    Controller(SolverClass solver);
    SolverClass solver;
    void func() { solver.func(); };
};

class System1Controller : Controller<System1Solver>;
class System2Controller : Controller<System2Solver>;

Edit: This example actually works. Thanks everyone for confirming this was an appropriate way to accomplish this.

/* Compile with g++ -O3 -std=c++14 -o crimes metaprogramming_crimes.cpp */

#include <iostream>

class AbstractSolver { virtual void func() = 0; };
class System1Solver : AbstractSolver { public: void func() override { }; };
class System2Solver : AbstractSolver { public: void func() override { }; };

/* 
class System1Controller { 
  public:
    System1Solver solver;
    void func() { solver.func(); };
};

class System2Controller { 
  public:
    System2Controller(System2Solver solver);
    System2Solver solver;
    void func() { solver.func(); };
}; 
*/

template <class SolverClass>
class Controller {
  public:
    SolverClass solver;
    void func() { solver.func(); };
};

class System1Controller : Controller<System1Solver> { };
class System2Controller : Controller<System2Solver> { };

auto main()->int {

    System1Controller controller1;
    System2Controller controller2;

    if (typeid(controller1) != typeid(controller2)) {
        std::cout << "Yay!" << std::endl;
    } else {
        std::cout << "Boo." << std::endl;
    }

};

Solution

  • Another option is to use polymorphism: keep a pointer to your AbstractSolver in the single Controller class, and pass appropriate concrete solver to the controller's constructor.