'Covariant return type on Eigen Matrix for base class method
Suppose that I have two different solvers that both will be called at run time.
- I want to call solvers' api and get resulted Eigen matrix through the base class pointer.
- The solved matrix size are selected from a few known values depending on some runtime variable. I need to use compiled time fixed size matrix in this case.
The solver derived class definitions are as follow.
template <int VarSize>
class SolverA : Solver {
public:
SolverA() {}
bool Solve() override {
// SolverA specific implementations.
}
const Eigen::Matrix<double, VarSize, 1>& solution() override {
return solution_;
}
private:
Eigen::Matrix<double, VarSize, 1> solution_;
}
template <int VarSize>
class SolverB : Solver {
public:
SolverB() {}
bool Solve() override {
// SolverB specific implementations.
}
const Eigen::Matrix<double, VarSize, 1>& solution() override {
return solution_;
}
private:
Eigen::Matrix<double, VarSize, 1> solution_;
}
Now the problem is how I can write the base class solution()
method to get the resulted Eigen matrix, since the template parameter VarSize
are not known in the base declaration.
class Solver {
public:
virtual bool Solve() = 0;
// not covariant type, won't compile.
// virtual const Eigen::VectorXd& solution() = 0;
}
constexpr int kEasyProbSize = 5;
constexpr int kHardProbSize = 20;
int main() {
Solver* solver;
if (GetComplexity() > 30) {
solver = &SolverB<kHardProbSize>();
} else {
solver = &SolverA<kEasyProbSize>();
}
solver->Solve();
std::cout << solver->solution() << std::endl;
}
Some thoughts:
Eigen::Matrix<double, VarSize, 1>
does not derive fromEigen::VectorXd
so it cannot override.- I also cannot use
const Eigen::MatrixBase<Derived>&
since there is no that derived information and virtual method won't allow template. - I need to call from base class pointer so I cannot make the base class a template class.
- The solved
solution_
is already allocated and doesn't make sense to return a copy or converted to a dynamic size matrix.
Is this fixed size matrix getting from base class pointer even possible?
Solution 1:[1]
The easiest solution would be to just store a VectorXd solution_;
inside Solver
itself. But if you insist on storing the actual solution vector only in the derived classes, you can have solution()
return an Eigen::Ref<const Eigen::VectorXd>
which can be created with just moving a pointer and a few integers:
class Solver {
public:
virtual bool Solve() = 0;
// not covariant type, won't compile.
using VecRef = Eigen::Ref<const Eigen::VectorXd> const;
virtual VecRef solution() = 0;
};
template <int VarSize>
class SolverA : public Solver {
public:
SolverA() {}
bool Solve() override {
// SolverA specific implementations.
return true;
}
Solver::VecRef solution() override {
return solution_;
}
private:
Eigen::Matrix<double, VarSize, 1> solution_;
};
template <int VarSize>
class SolverB : public Solver {
public:
SolverB() {}
bool Solve() override {
// SolverB specific implementations.
return true;
}
VecRef solution() override {
return solution_;
}
private:
Eigen::Matrix<double, VarSize, 1> solution_;
};
Godbolt demo: https://godbolt.org/z/MqaofsoK9
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | chtz |