Мне нужно решить, по крайней мере для меня, каверзную задачу на C++. Есть dll, которую я не могу изменить. Он получает указатель на функцию в качестве аргумента. Если я передаю указатель на глобальную функцию, все работает нормально. К сожалению, существует список объектов того же класса для передачи в dll. В С# я решил это с помощью делегатов. Как это можно сделать на С++? Использование std::function не работает. При этом во время выполнения возникают ошибки соглашения о кодировании. Дальнейшее использование MSVC2010 было бы оптимальным. Я написал образец, который описывает проблему:
#include <stdio.h>
// global function which works
void __stdcall task_global(float x, float y) { printf("Called global function with: %f %f\n", x, y); }
typedef void(__stdcall *f_pointer)(float, float);
// try of using a member function
class BaseTask {
public:
virtual void __stdcall task(float x, float y) = 0;
};
class ListeningTask :public BaseTask {
public:
void __stdcall task(float x, float y) { printf("Called this member function with: %f %f\n", x, y); }
};
typedef void (BaseTask::*member_f_pointer)(float, float);
// the dll to use
class RegisterTask {
public:
// no posibility to access or modify!
void __stdcall subscribe(f_pointer fp) { fp(1.0f, 2.0f); }
// just for demonstration how to use a member function pointer
void __stdcall subscribeMemberDemo(member_f_pointer mfp) { /*how to use mfp?*/};
};
int main() {
RegisterTask register_task{};
// use global function
f_pointer pointer_to_global_task = task_global;
register_task.subscribe(pointer_to_global_task);
/*---------------------------------------------------------------*/
// use member function?
std::list<ListeningTask> listening_task_list;
for(int i = 0; i < 10; i++) {
listening_task_list.push_back(ListeningTask lt);
member_f_pointer pointer_to_member_task = &listening_task_list.back().task; //error C2276: '&': illegal operation on bound member function expression
register_task.subscribeMemberDemo(pointer_to_member_task);
// the tricky and important one to solve
// how to pass the member function to this subscribe(f_pointer)?
register_task.subscribe(pointer_to_member_task);
}
getchar();
return 0;
}
Важный вопрос заключается в том, как передать указатель функции-члена в RegisterTask::subscribe(f_pointer)
?
Вопрос в скобках: как передать функцию-член в RegisterTask::subscribeMemberDemo(member_f_pointer)
?
Я надеюсь, что кто-то может помочь мне решить эту проблему? Я работаю над этим со дня.
Изменить: я изменил вопрос, чтобы подчеркнуть проблему со списком ListenerTask
. Как передать указатель функции-члена, теперь мне ясно из ответов @pokey909 и @AndyG. Оба они предоставляют указатель на один объект или, скорее, на список объектов. Если обратный вызов вызывается, то один ListenerTask
или все std::list<*ListenerTask>
вызываются одновременно. Но как сделать, чтобы вызывался только один ListenerTask
из списка. Передача нескольких обратных вызовов в dll. Он (RegisterTask
) может это сделать, потому что работает следующий пример с глобальными функциями.
void __stdcall task_global_1(float x, float y) { printf("Called global function 1 with: %f %f\n", x, y); }
void __stdcall task_global_2(float x, float y) { printf("Called global function 2 with: %f %f\n", x, y); }
void __stdcall task_global_3(float x, float y) { printf("Called global function 3 with: %f %f\n", x, y); }
typedef void(__stdcall *f_pointer)(float, float);
int main() {
// give the functions to the dll.
f_pointer pointer_to_global_task_1 = task_global_1;
register_task.subscribe(pointer_to_global_task_1);
f_pointer pointer_to_global_task_2 = task_global_2;
register_task.subscribe(pointer_to_global_task_2);
f_pointer pointer_to_global_task_3 = task_global_3;
register_task.subscribe(pointer_to_global_task_3);
}
Есть три глобальных указателя функций. Все они отданы dll. Теперь, если у dll есть задача на task_global_2
, она уведомляет только об этом! Как добиться этого различия с помощью указателя на функцию-член?
Примечание. Я получил источник dll. Надеюсь это поможет. К сожалению модификация, сборка невозможна. Вот определение обратного вызова:
type TCallback = procedure( x : single; y : single; ); stdcall;
procedure subscribe(aCallback: TCallback ); StdCall;
begin
TaskSocket.addTask( aCallback );
end;
procedure TSocket.addTask( aCallback : TCallback);
var newTask : TTask;
begin
newTask := TTask.Create(aCallback);
TaskList.addItem(newTask);
end;
std::bind
- person AndyG   schedule 20.09.2016this
доставит вас. Вместо этого передайте статический метод, который вызывает метод, который вы хотите выполнить, в dll. Вам придется найти какой-то способ узнать, какой объект вызывать в статическом методе. Если у вас есть только один экземпляр объекта, это будет легко. Если не... - person user4581301   schedule 20.09.2016RegisterTask::subscribe
не объявлен статическим? Он не используетthis
. - person Barmar   schedule 20.09.2016void *
, который будет использоваться в качестве параметра функции обратного вызова, чтобы можно было мультиплексировать несколько получателей. Это быстро решает вопрос Какой объект я должен вызывать? проблема. - person user4581301   schedule 20.09.2016RegisterTask
У меня есть только dll. - person solarisx   schedule 20.09.2016subscribe
в указатель на функцию, а не передавать ему указатель на функцию в качестве аргумента. - person Barmar   schedule 20.09.2016float
. Таким образом, нет аргументаvoid *
, который может содержать указатель на объект. - person Barmar   schedule 20.09.2016void(*)(float,float)
вsubscribe
? Я думаю, что это. В настоящее время я вне офиса, поэтому я буду тестировать его завтра. Как использовать его сvoid(*)(float, float)
? - person solarisx   schedule 20.09.2016void (*f)(void*, float, float)
, где аргументvoid*
является непрозрачным указателем, который будет использоваться функцией обратного вызова. - person Barmar   schedule 20.09.2016public delegate void TaskDelegate(float x, float y);
, которые указывают на объекты. - person solarisx   schedule 20.09.2016