C++ factory of a class that specializes a templated superclass

Viewed 64

I'm developing a C++ framework for mathematical optimization and I'm struggling to find a good design for my sparse matrix representations.
Basically:

  • I have two sparse matrix representations: types A and B ;
  • I have (say) four linear solvers, Alan, Alicia, Beth and Benjamin. Alan and Alicia works exclusively with A matrices, Beth and Benjamin with B matrices ;
  • I'd like to template my code so that choosing a linear solver at runtime sets the type of all the matrices (type A or B) in the rest of the code (so that the matrix of the linear system is generated directly in the right format).

I tried the following (simplified) code:

template <class MatrixType>
class LinearSolver {
   virtual void factorize(const MatrixType& matrix) = 0;
}

class LinearSolverAlan: public LinearSolver<MatrixTypeA> {
   void factorize(const MatrixTypeA& matrix) override;
}

class LinearSolverAlicia: public LinearSolver<MatrixTypeA> {
   void factorize(const MatrixTypeA& matrix) override;
}

class LinearSolverBeth: public LinearSolver<MatrixTypeB> {
   void factorize(const MatrixTypeB& matrix) override;
}

class LinearSolverBenjamin: public LinearSolver<MatrixTypeB> {
   void factorize(const MatrixTypeB& matrix) override;
}

The common supertype of the solvers is the template type LinearSolver, so I templated the factory as well:

template<class MatrixType>
class LinearSolverFactory {
public:
   std::unique_ptr<LinearSolver<MatrixType> > create(const std::string& solver_name) {
     if (solver_name == "alan") {
        return std::make_unique<LinearSolverAlan>();
     }
     else if (...) {
        ...
     }
   }
};

Then on a higher level, I call LinearSolverFactory::create() with the right solver name and template parameter.

However it won't compile (std::unique_ptr<LinearSolverAlan> cannot be converted to a std::unique_ptr<LinearSolver<MatrixTypeA> >). I'm not good enough at templates to see whether the problem can be fixed.

Thanks for your help :)

Charlie

1 Answers

LinearSolverAlan and LinearSolverBeth do not share a common base, because LinearSolver<MatrixTypeA> and LinearSolver<MatrixTypeB> are two unrelated types.

You can use either if constexpr to discard the branches that are not used in the specific instantation of the factory or specialize the whole factory:

template <typename MatrixType>
struct Factory;

template <> 
struct Factory<MatrixTypeA> {
   std::unique_ptr<LinearSolver<MatrixTypeA> > create(const std::string& name) {
         // select a LinearSolve<MatrixTypeA> and return it
   }
};

template <> 
struct Factory<MatrixTypeB> {
   std::unique_ptr<LinearSolver<MatrixTypeB> > create(const std::string& name) {
         // select a LinearSolver<MatrixTypeB> and return it
   }
};

Another alternative is to make LinearSolver<MatrixTypeB> and LinearSovler<MatrixTypeB> inherit from a common (non template) base class.

Related