【发布时间】:2019-10-24 15:10:13
【问题描述】:
受另一篇关于 SO (C++ callback using class member) 的文章启发,我尝试编写一个通用的 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"
我想在其他几个模板化命名空间/类中使用它,比如这里:
包装器.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 *));
}
包装器.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>();
}
}
我想像这样使用回调:
我的模块.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 可移植和工作,同时具有易于使用的界面。
编辑: 我试图在代码上应用 cmets 建议,但我要快 声称第一个问题得到了解决。该错误只是被下一个错误隐藏了。如果我尝试仅使用这一行进行编译:
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); };
}
【问题讨论】:
-
旁注:
std::move是不必要的。你只需要它把命名的东西变成临时的(粗略地说)。函数返回值根据定义是临时的,将自动移出。 -
您能否更正或验证您确实希望在标题中包含
MyModule GetNewModule(...);而在 .cpp 中包含Screenshotmodul GetNewScreenshotmodul(...);? -
第一个错误表示您想将不带参数的函数指针传递给需要带参数的
std::function的函数。必须同意编译器:method不接受任何参数,因此您不能将其用作接受CallbackArgType的std::function。随后的std::bind失败可能是这个早期错误的结果。 -
无论如何,我无法摆脱你在这里过于复杂化的感觉......
-
哦,我现在明白了。您正在尝试使用成员
std::function,就好像它是成员函数一样。那是行不通的。但使用 lambda 是一个很好的理由。
标签: c++ templates callback function-pointers std-function