Violet Giraffe
Violet Giraffe

Reputation: 33579

Taking a pointer to a protected method of the base class and passing it to a different class

template <typename... Arguments>
class CCallback
{
public:
    template <class TargetClass>
    CCallback(TargetClass * target, void (TargetClass::*targetMethod)(Arguments...))
    {
    }
};

struct TargetClassBase
{
protected:
    void f() {}
};

struct TargetClassChild : TargetClassBase
{
    void g() {}

    void test()
    {
        CCallback<> callback(this, &TargetClassChild::f);
    }
} child;


void main()
{
}

That code doesn't compile in MSVC 2013:

error C2660: 'CCallback<>::CCallback' : function does not take 2 arguments

I don't understand why I get this specific error, and how to make it work. There are no further details about the error logged by the compiler.

And, of course, I can't properly specify that the method belongs to the base class (&TargetClassBase::f)- taking a pointer to a non-public base method is forbidden.

Upvotes: 1

Views: 190

Answers (2)

Violet Giraffe
Violet Giraffe

Reputation: 33579

Expanding on robal's perfectly correct answer, I've rewritten the constructor of my class so that I don't need a manual type cast:

template <class TargetInstanceClass, class TargetMethodClass>
CCallback(TargetInstanceClass * target, void (TargetMethodClass::*targetMethod)(Arguments...))
{
   void (TargetInstanceClass::*targetInstanceMethod)(Arguments...) = static_cast<void (TargetInstanceClass::*targetInstanceMethod)(Arguments...)>(targetMethod);
}

Upvotes: 0

robal
robal

Reputation: 368

Problem with your code is that compiler cannot deduce template type TargetClass in constructor for CCallback. This is because you pass arguments of types: TargetClassChild* and void (TargetClassBase::*)() to constructor. This is not a typo. Even if you write &TargetClassChild::f this expression still has type: pointer to function returning void in class TargetClassBase and not TargetClassChild as one could expect.

This kind of issues can be solved in two ways:

  1. You could specify template type explicitly, but in this particular case it cannot be done because in C++ there is no way to explicitly pass template parameters to constructors as constructors don't have names (according to note in §14.5.2.5 of c++ standard).
  2. Pass arguments of appropriate types to function. In this case simply cast your function to appropriate type like this static_cast<void (TargetClassChild::*)()>(&TargetClassChild::f)

Upvotes: 1

Related Questions