Nasha Nasha - 1 month ago 7
C++ Question

Pointer to member type incompatible with object type when calling a pointer to a member of a derived class

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?

Answer

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.