I understand that virtual functions cannot be templated, but is there a way that derived classes implement a generic function and the virtual function requires sucha generic function to have at least certain arguments? I provide two examples, the first of which is the simplified example and the second of which is a more realistic motivation for what I want to do (I am a C++ beginner, so I could be way off in my thinking).
Simplified:
class Base
{
public:
template<class T>
virtual T foo(T a, T b, ...) = 0;
};
class DerivedSimple : public Base
{
public:
// Meets the minimum argument requirements in the Base class
template<class T>
T foo(T a, T b) override;
};
class DerivedExtended : public Base
{
public:
// Has the minimum required args AND an arg specific to this class
template<class T>
T foo(T a, T b, int some_special_argument) override;
};
Extended:
#include <Eigen/Core>
#include <Eigen/Sparse>
class SmootherBase
{
public:
/**
* @brief Derived types must implement a `smooth` function that smooths `Au = b`.
*
*/
template <class T>
virtual Eigen::Matrix<T, -1, 1> smooth (
const Eigen::SparseMatrix<T>& A, // <--|
const Eigen::Matrix<T, -1, 1>& u0,// |
const Eigen::Matrix<T, -1, 1>& b, // | must have these args
const size_t niters, // <--|
... // optional args for different smoother
) = 0;
};
class SuccessiveOverRelaxation : public SmootherBase
{
private:
public:
template <class T>
Eigen::Matrix<T, -1, 1> smooth (
const Eigen::SparseMatrix<T>& A, // <--|
const Eigen::Matrix<T, -1, 1>& b, // | The required arguments
const Eigen::Matrix<T, -1, 1>& u0,// |
const size_t niters, // <--|
const float omega // An argument specific to this smoother
) override;
};
class Jacobi : public SmootherBase
{
private:
public:
template <class T>
Eigen::Matrix<T, -1, 1> smooth (
const Eigen::SparseMatrix<T>& A, // <--|
const Eigen::Matrix<T, -1, 1>& u0,// |
const Eigen::Matrix<T, -1, 1>& b, // | The required arguments
const size_t niters, // <--|
) override;
};
You cannot override a function that has a different signature. If you're sending these extra arguments to the class purely to affect its behavior (e.g. configuration options), then consider changing your approach so that you provide them in the constructor and use them in foo()
.
As you already mentioned, you cannot template virtual functions. So it's odd that you did exactly that in your examples.
Here's the approach I describe above:
template<class T>
class Base
{
public:
virtual T foo(T a, T b) = 0;
};
template<class T>
class DerivedSimple : public Base<T>
{
public:
T foo(T a, T b) override;
};
template<class T>
class DerivedExtended : public Base<T>
{
public:
DerivedExtended(int some_special_argument)
: some_special_argument(some_special_argument)
{}
T foo(T a, T b) override;
protected:
int some_special_argument;
};