1
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.

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335

2 Answers2

1

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)
robal
  • 368
  • 2
  • 8
  • Great, that works! And so does this: `CCallback<> callback((TargetClassBase*)this, &TargetClassChild::f);` – Violet Giraffe Jan 06 '15 at 15:17
  • But still, why does MSVC throw this exact warning and not something more informative like type mismatch, ambiguous template parameter type deduction etc.? – Violet Giraffe Jan 06 '15 at 15:29
0

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);
}
Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335