Шаблонный класс универсального обратного вызова с указателем на обратный вызов метода - PullRequest
0 голосов
/ 24 октября 2019

Вдохновленный другой статьей о 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); };
}

1 Ответ

0 голосов
/ 25 октября 2019

Заменить

m_parentCallback = std::bind(&CallbackHandler<ParentClass, wxImage*>::m_callbackFunc, handler, std::placeholders::_1);

на

m_parentCallback = [handler](auto img){ handler->m_parentCallback(img); };

Я не думаю, что bind был разработан для работы с объектами-функторами элементов поверх всего. Но лямбды справляются с этим без проблем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...