Вдохновленный другой статьей о SO ( C ++ callback с использованием члена класса ) Я попытался написать универсальный CallbackHandler.
CallbackHandler.hpp
#pragma once
#include <functional>
template <typename CallbackClass, typename CallbackArgType>
class CallbackHandler
{
public:
std::function<void(CallbackArgType ct)> m_callbackFunc;
CallbackHandler(CallbackClass * handler, std::function<void(CallbackArgType)> method)
{
//m_callbackFunc is supposed to stand for a member to pointer callback function with one
//parameter of any type
m_callbackFunc = std::bind(method, handler, std::placeholders::_1);
}
};
#include "wrapper_T.cpp"
IЯ хочу использовать его в нескольких других шаблонных пространствах имен / классах, таких как здесь:
wrapper.hpp
//this wrappers main purpose is to combine the constructor of a non templated class (MyModule)
//and hold a (global) callback method for it (m_parentCallback)
namespace wrapper
{
extern std::function<void(wxImage *)> m_parentCallback;
template<typename ParentClass>
MyModule GetNewModule(ParentClass* parent, void (ParentClass::* method)(wxImage *));
}
wrapper.cpp
namespace wrapper
{
//This is only to avoid multiple definition error - actual definition is in wrapper_T.cpp
std::function<void(wxImage *)> m_parentCallback;
}
wrapper_T.cpp
namespace wrapper
{
template<typename ParentClass>
MyModule GetNewModule(ParentClass* parent, void (ParentClass::* method)(wxImage *))
{
//the callback type of this wrapper/class is wxImage*
std::shared_ptr<CallbackHandler<ParentClass, wxImage*>> handler =
std::make_shared< CallbackHandler<ParentClass, wxImage*>>(parent, method);
//EDIT - SOLVED: <- Error C2664: Cant convert argument 2 from "void (__thiscall MyModule::*)(void)" to "std::function<void(wxImage*)>"
m_parentCallback = std::bind(&CallbackHandler<ParentClass, wxImage*>::m_callbackFunc, handler, std::placeholders::_1);
//<- Error C2679: no suitable binary operator "=" found
return std::make_unique<MyModule>();
}
}
Я хотел использовать обратный вызов следующим образом:
MyModule.cpp
wrapper::m_parentCallback(&img);
Я хочу инициализировать все это так:
MainClass.cpp
MainClass::MainClass()
{
//declared in header: std::unique_ptr<MyModule> module
module = std::move(wrapper::GetNewModule(this, &MainClass::CallbackFunc));
}
void MainClass::CallbackFunc(wxImage * img)
{ /* do something with it */ }
У меня есть класс с указателем "this" и указателем на метод "CallbackFunc", который должен быть в порядке. Но я не понимаю, как использовать мой класс CallbackHandler для указателя обратного вызова std :: function.
Или я переборщил с оберткой, содержащей указатель на метод CallbackHandler, который содержит указатель на методфактического метода обратного вызова?
Все это не является выбором дизайна, я просто хочу, чтобы CallbackHandler был переносимым и работающим, но имел интерфейс, который прост в использовании.
РЕДАКТИРОВАТЬ: Я пытался применить комментарии предложения к коду, но я был быстро с утверждением, что первая проблема была решена. Ошибка была просто скрыта следующей ошибкой. Если я попытаюсь скомпилировать только с этой строкой:
std::shared_ptr<CallbackHandler<ParentClass, wxImage*>> handler =
std::make_shared< CallbackHandler<ParentClass, wxImage*>>(parent, method);
//<- Error C2664: "CallbackHandler<ParentClass,wxImage *>::
//CallbackHandler(CallbackHandler<ParentClass,wxImage *> &&)"
//: converting argument 2 from "void (__thiscall MainClass::* )(wxImage *)"
//to "std::function<void (wxImage *)>" not possible
// with
// [
// ParentClass=MainClass
]
//(freely translated into english by me)
Итак, пропущенный аргумент был не единственной проблемой. Если std :: bind для методов (функций-членов) не работает, я должен также изменить CallbackClass, не так ли? Может быть, что-то в этом роде:
std::function<void(CallbackArgType cat)> m_callbackFunc;
CallbackHandler(CallbackClass * handler, std::function<void(CallbackArgType)> method)
{
//m_callbackFunc = std::bind(method, handler, std::placeholders::_1);
m_callbackFunc = [method](auto img) { method(img); };
}