I know this question gets asked a lot, but I have a specific use case, so I don't think it's a duplicate!
I have an abstract base class:
template<int N>
class Child;
class Base
{
public:
// Factory-like generation of children as Base
static Ptr<Base> New(int baseN)
{
if (baseN == 2) return new Child<2>();
else if (baseN == 3) return new Child<3>()
}
// Update
virtual void update() = 0;
};
And I'm writing some children of Base
as class templates (on an int):
template<int N>
class Child
:
public Base
{
// Member, N is not the size of matrix, more like the size of a component in matrix
Matrix<N> m_member;
public:
// Implement update
virtual void update();
// Should call the passed callable on m_member
virtual void execute(std::function<void(Matrix<N>&)>&);
};
// Force compilation of Child<N> for some values of N (of interest, including 3) here
// Then,
int baseN = 3;
Ptr<Base> obj = Base::New(baseN); // will get me a Child<3> as a Base object
auto callable = [](Matrix<3>) ->void {};
// Can I access Child<3>::m_member ??
// Can't cast to Child<baseN> (baseN is not constexpr) and don't want to
// But want to do something like:
obj->execute(callable);
// Which forwards 'callable' to the method from concrete type, probably using a cast?
In short, I need to have some sort of access to m_member
from the declared Base
object.
Preferably, a way to call Child<N>::execute
from Base
without making Base a template on N too.
Things I've tried/thought-of include:
- 'Type erasure' of
Matrix<N>
by hiding them behind an interface, but becauseMatrix<N>
's interface strongly depends on N, doing that renders the classes useless (think:Vector<N>& Matrix<N>::diag()
for example) - Can
Base::New
do anything to record what concrete type it creates? I doubt that because types are not objects.
CodePudding user response:
It seems you want inheritance to group not so related classes...
std::variant
(C 17) might be more appropriate:
template<int N>
class Child
{
// Member, N is not the size of matrix, more like the size of a component in matrix
Matrix<N> m_member;
public:
void update();
void execute(std::function<void(Matrix<N>&)> f) { f(m_member); }
};
using Base = std::variant<Child<2>, Child<3>>;
and then:
void foo(Base& obj)
{
struct Visitor {
template <std::size_t N>
void operator()(Child<N>& c) const
{
auto callable = [](Matrix<N>) -> void {/*..*/};
c.execute(callable);
}
} visitor;
std::visit(visitor, obj);
}