Неразрешенный внешний символ с самодельным делегатом

У меня есть функция Foo, которая принимает в качестве параметра двухпараметрическую функцию:

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

Однако тип функции, которую я хочу передать (func), принимает только 1 параметр *.

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

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

В C # я бы сделал что-то вроде:

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

Я пытаюсь сделать что-то подобное с классом делегата (выяснив, что у меня не может быть указателя на связанную функцию-член, я переключился на статический):

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); }

Что я использую так:

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

В настоящее время это вызывает ошибку компоновщика: unresolved external symbol "private: static void (__stdcall* Delegate::_Callback)(int)" (?_Callback@Delegate@@0P6GXHHPAN0@ZA)

  • Вопрос 1. Что могло вызвать эту ошибку компоновщика?
  • Вопрос 2: есть ли лучший способ сделать это?

* Функция typedef включает __stdcall, потому что она передается из (и будет вызывать обратно) C #)


person Benjol    schedule 04.06.2012    source источник
comment
Я думаю, что наличие класса Delegate - плохая идея в этой ситуации. Это дает вам иллюзию обертывания функции в экземпляре класса, тогда как на самом деле фактически вызываемая функция зависит от того, из чего был построен последний экземпляр Delegate, который должен быть построен. Delegate::_Callback - это фактически глобальные данные.   -  person CB Bailey    schedule 04.06.2012
comment
@CharlesBailey, да, я это понимаю, так что бы вы сделали, перестаньте притворяться и просто сделайте это глобальной функцией?   -  person Benjol    schedule 04.06.2012


Ответы (2)


Как я указал в своем комментарии, использование класса создает впечатление, что вы обернули функцию обратного вызова в экземпляр класса, но поскольку функция обратного вызова является необработанным указателем на функцию, она не может получить доступ к любому состоянию из экземпляра класса, которое было получен из. Он может получить доступ только к статическим переменным-членам, а это означает, что поведение всех Delegate экземпляров при создании нового Delegate экземпляра.

Если вам нужно поддерживать вызов разных func, я бы использовал более простой интерфейс, который делает тот факт, что только функция обратного вызова активна в одно время, более очевидным из интерфейса.

Например:

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;
}
person CB Bailey    schedule 04.06.2012

Вам нужно определить static членов классов ровно один раз (например, в Delegate.cpp):

FuncCallBack Delegate::_Callback;

В опубликованном коде есть только объявление _Callback.

person hmjd    schedule 04.06.2012
comment
Превосходно! Спасибо. Слишком много лет в C # стерли мой небольшой опыт в C ++. - person Benjol; 04.06.2012