1

I have a function Foo which takes a 2-parameter function as a parameter:

void Foo(void (*fcn)(int, int*));

However, the type of function which I want to pass in (func) only takes 1 parameter*.

typedef void (__stdcall *FuncCallBack)(int a);

void Caller(FuncCallBack func) {
   Foo(????);
}

In C#, I would do something like:

Foo((a,b) -> func(a));

I'm trying to do something similar with a delegate class (having worked out that I can't have a pointer to a bound member function, I've switched to static):

class Delegate {
private:
 static FuncCallBack _Callback;
public
 Delegate(FuncCallBack);
 static void Callback(int, int*);
}

Delegate::Delegate(FuncCallback callback) { _Callback = callback; }

void Delegate::Callback(int a, int *b) { _Callback(a); }

Which I use like so:

void Caller(FuncCallBack func) {
   Delegate d = Delegate(func);
   Foo(&(d.Callback));
}

This is currently giving me a linker error: unresolved external symbol "private: static void (__stdcall* Delegate::_Callback)(int)" (?_Callback@Delegate@@0P6GXHHPAN0@ZA)

  • Question 1: What could be causing this linker error?
  • Question 2: Is there a better way to do this?

*The function typedef includes __stdcall because it is passed in from (and will be calling back to) C#)

Benjol
  • 63,995
  • 54
  • 186
  • 268
  • 1
    I think having a `Delegate` class is a bad idea for this situation. It is giving you the illusion of having wrapped the function in a class instance whereas in reality the function actually called depends on what the last instance of `Delegate` to be constructed was constructed with. `Delegate::_Callback` is effectively global data. – CB Bailey Jun 04 '12 at 10:24
  • @CharlesBailey, yes, I realise that, so what would you do, stop pretending and just make it a global function too? – Benjol Jun 04 '12 at 10:31

2 Answers2

2

You need to define the static members of classes, exactly once (in Delegate.cpp for example):

FuncCallBack Delegate::_Callback;

In the posted code there is only a declaration of _Callback.

Benjol
  • 63,995
  • 54
  • 186
  • 268
hmjd
  • 120,187
  • 20
  • 207
  • 252
2

As I pointed out in my comment, using a class makes it seem like you've wrapped the callback function in a class instance but as the callback function is a raw function pointer it can't access any state from the class instance that it was obtained from. It can only access static member variables and this means that the behaviour for all Delegate instances whenever a new Delegate instance is constructed.

If you have to support calling different func I would use a simpler interface that makes the fact that only callback function is active at one time more evident from the interface.

For example:

callbackwrapper.h:

void CallbackWrapper(int, int*);
void SetWrappedCallback(void (__stdcall *toWrap)(int));

callbackwrapper.cpp:

namespace {
    void (__stdcall *wrappedCallback)(int);
}

void CallbackWrapper(int a, int*)
{
    wrappedCallback(a);
}

void SetWrappedCallback(void (__stdcall *toWrap)(int))
{
    wrappedCallback = toWrap;
}
CB Bailey
  • 755,051
  • 104
  • 632
  • 656