I have defined a class template such as this one:
template <const category_id_t category, class Base>
class Node : public Base
{
...
template <typename Derived, class T>
void on_message( const frame_t& frame, void (Derived::*call)(const T*) )
{
if ( frame.length == sizeof(T) )
(this->*(call))((T*)frame.data);
}
}
The argument category
serves as a token to implement several similar classes and provide proper specialization according to specific categories. The above class is then derived like this:
template <class Base>
class Sys : public Node<CID_SYS, Base>
{
Sys() : Node<CID_SYS, Base>() { /* ... */ }
....
};
Class Sys
is only a class that provides an base interface to objects of category CID_SYS
(enum, value = 5) and serves as a base class to the actual implementation of the interface:
class SysImpl : public Sys<CAN>
{
...
/* Parse remote notifications */
void on_notify( const state_info_t* ) { /* ... */ }
};
SysImpl sys;
Finally I have a function that calls the base class Node<CID_SYS, Base>
member function on_message()
like this:
void foo(const frame_t& frame)
{ sys.on_message(frame, &SysImpl::on_notify ); }
The compiler throws an error around the line (this->*(call))((T*)frame.data)
saying
error: pointer to member type 'void (SysImpl::)(const state_info_t*)' is incompatible with object type 'Node<(category_id_t)5u, CAN>'
The compiler has successfully guessed what template function to call, it's just that it doesn't seem to "recognize" that this
is from a derived class.
What I'd like is to call any member function of a class derived from Node<CID_SYS, CAN>
, not only stand-alone functions (which works perfectly well so far, not shown in the excerpt above).
What am I missing?
In the on_message
function the variable this
is not a pointer to SysImpl
, it's type is Node<CID_SYS, CAN>*
. The Node
template class have no member on_notify
so you can't call it on an instance of Node
. It must be called on an instance of Derived
(which should be SysImpl
).
That's why you get the error and need to cast this
to Derived*
:
(static_cast<Derived*>(this)->*(call))(...);
Of course, this only works if Derived
actually is derived from the Node
class.