I'm trying to create the following flow:
Having a 'Base' class, with no params or functionality, just so i can hold Base pointers in a method.
Its derived class, is a template, which implements operator() on given template argument object type.
I'm trying, by using a pointer to base class, call the derived class operator(), in run-time.
I've tried implementing it using CRTP (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) But that doesn't seem to work the-other-way-around - when the derived class is a class template.
Here is my code:
class Base {};
template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;
public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}
inline bool operator()(const Obj_Type& obj) const {
return (m_db.*m_func)(obj);
}
}
Now, usage is in another class template, that contains vector of Base class pointers, as follows, and have its own operator() :
template<typename Obj_Type2> /* Upon usage, Obj_Type2 is the same as Obj_Type, this is just to differ the two in the code here */
class BlaBla {
private:
std::vector<const Base *> m_vec;
public:
/* relevant constructors ... */
inline bool operator()(const Obj_Type2 &obj) const {
for(std::vector<const Base *>::const_iterator it = m_vec.begin(); it != m_vec.end(); ++it) {
/*** This is the problematic line V ***/
if( (*it).operator()(obj) ) { /* DO SOMETHING */ }
}
}
Of course the compiler is complaining that there is no matching function to call for in the problematic line that is marked in the code below, but i can't figure out a way to do the relevant call.
1st Solution that came to mind, is to create a virtual operator()(...), with a specific object type e.g. virtual operator()(const uint32_t &obj) in Base class, which works, but my intention is that operator()(...) will receive a variety of object types, and stating a virtual method for each of them is not elegant and seems to break all the template concept i want to implement here.
2nd Solution that came to mind, is somehow passing Ref_Obj and Obj_Type typenames to Base class, to be used in sort of interface method, that will use static_cast to call the appropriate Derived operator (As in CRTP) - But that doesn't seem to work because Derived class is a class template, and also BlaBla class doesn't directly know Ref_Obj typename.
Is there any other way to make the appropriate call to Deriver operator()
There is no clear clean way to do this. The fundamental problem is that there is no such thing as a virtual template method.
The cleanest way I can think of doing this that implements complete type erasure is with a dynamic cast, and a virtual method:
class Base {
public:
virtual bool operator()(const Base &) const=0;
};
template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;
public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}
inline bool operator()(const Base& obj) const override {
const Obj_Type *derived_obj=dynamic_cast<const Obj_Type *>(&obj);
if (!derived_obj)
{
throw; // Or maybe return false, or something...
}
return (m_db.*m_func)(*derived_obj);
}
};
Obj_Type
must also be derived from Base
. This gets the job done at runtime, but there is no compile-time type-checking.
The other approach is to bite the bullet, and forego 100% type erasure:
template<typename Obj_Type>
class Base {
public:
virtual bool operator()(const Obj_Type &) const=0;
};
template<typename Ref_Obj, typename Obj_Type>
class Derived : public Base<Obj_Type> {
private:
typedef bool (Ref_Obj::*Func_p)(Obj_Type) const;
Func_p m_func;
const Ref_Obj& m_db;
public:
Derived<Ref_Obj, Obj_Type>(const Ref_Obj& db, Func_p func): m_db(base), m_func(filter) {}
inline bool operator()(const Obj_Type& obj) const override {
return (m_db.*m_func)(obj);
}
};
So, you can still abstract away operator()
on some object to its pure interface, and define the details in the subclass.
Or, another alternative would be a combination of the two:
class SuperBase {
public:
virtual bool operator()(const Base &) const=0;
};
template<typename Obj_Type>
class Base : public SuperBase {
public:
virtual bool operator()(const Obj_Type &) const=0;
bool operator()(const Base &obj) const override
{
// Do the dynamic cast check, and forward it to the other
// operator().
}
};
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments