如何创建一个填充了 C 风格函数指针和 lambda 的向量(有和没有捕获)
Posted
技术标签:
【中文标题】如何创建一个填充了 C 风格函数指针和 lambda 的向量(有和没有捕获)【英文标题】:How to create a vector filled with C-Style function pointers and lambdas(with and without captures) 【发布时间】:2019-10-16 19:11:27 【问题描述】:我最近一直在学习 lambda 和函数指针,并想在一个简单的回调系统中使用它们。
存储事件和触发时应调用的所有回调的映射如下所示:std::unordered_map< sf::Event::EventType , std::vector< Callback > > eventMap;
。
我是这样定义回调的
typedef void(*Callback)(sf::Event const&);
。我的registerEvent()
函数接受一个事件和一个回调作为参数。registerEvent()
然后可以这样调用:
inputHandler.registerEvent(/*Any event type*/, [](sf::Event const&)
//do something
);
这很好,但是当我想捕获一个对象时,我得到一个编译错误说
error: no matching function for call to ‘InputHandler::registerEvent(sf::Event::EventType, Button::Button(ID, Callback, InputHandler&)::<lambda(const sf::Event&)>)’
产生该错误的代码如下:
class Button
//
public:
Button(ID id, Callback callback, InputHandler& inputhandler)
inputhandler.registerEvent(sf::Event::MouseButtonPressed, [this](sf::Event const&)
getTextureRect();
);
;
似乎this
捕获正在更改 lambda 的类型,这使其与 registerEvent()
函数不兼容。但是由于许多不同的类应该能够创建这样的 lambda,并且向量中应该包含没有任何捕获的 lambda,所以我不知道如何判断向量应该是什么类型。我听说过std::function
,但是(这听起来可能很傻)我想使用 C 风格的方式来更好地理解。我认为this 帖子对此有所说明,但我不太了解它。我考虑过创建两张地图,一张用于所有无捕获的 lambda,一张用于其他。然后我可以让每个类都从基类继承,并使向量中的捕获类型成为指向基类的指针,尽管这非常复杂并且增加了不必要的开销,我什至不知道这是否可行。
对于这种情况,一般的解决方案是什么?
感谢所有回复和问候,
丹尼尔·施赖伯·门德斯 :)
编辑:
回调现在看起来像这样:
typedef std::function< void(sf::Event const&) > Callback;
当我想使用它时:
//inside the Button Constructor
inputhandler.registerEvent(sf::Event::MouseButtonPressed, Callback([this](sf::Event const& event)
//memberFunc();
));
这并没有给我一个错误,而是以错误的方式表现。它确实执行了 lambda,但没有更改定义它的类。所以我在构造函数中添加了一行,它只打印刚刚创建的对象的地址。我只创建一个按钮,所以应该只打印一个地址。但有两种不同。这意味着当将包装在 std::function 中的 lambda 插入向量时,会创建一个新的 Button 对象。怎么可能?隐式创建对象?
感谢您的回答:)
【问题讨论】:
Simliar issue. 【参考方案1】:带有捕获的 Lambda 不能转换为函数指针。普通函数指针没有任何地方可以存储 lambda 捕获的状态。
std::function
是一个对象,因此可以存储带有或不带有捕获的 lambda。
如果必须使用原始函数指针,则需要存储函数指针和状态,然后在调用时将状态传递给函数。例如
typedef void(*Callback)(sf::Event const&, void* data);
std::unordered_map< sf::Event::EventType , std::vector< std::pair< Callback, void* > > > eventMap;
然后您需要将您的状态存储在一个对象中,将该对象存储在某个位置以使其保持活动状态。在您的对象内部,您需要从 void*
转换回您的状态对象指针。如果您不使用需要普通函数指针的 c 库,那么使用 std::function
为您完成所有这些操作确实要简单得多。
【讨论】:
哦,好的,谢谢。使用 std::function 的解决方案大致是什么样的? 只需将您的 typedef 更改为typedef std::function<void(sf::Event const&)> Callback;
,std::function
几乎就像一个普通的函数指针,除了您可以为它们分配任何类型的仿函数(包括 lambda)
谢谢艾伦;关于“然后你需要将你的状态存储在一个对象中”:你的意思是例如this
作为一个州?那么void* data
是调用 lambda 的对象的参数吗?
您可以根据需要在函数中使用它。坚持std::function
,除非你真的需要做一些不同的事情
你应该问一个新问题(如果你愿意,可以链接回这个问题)而不是在你现有的问题中编辑一个新问题以上是关于如何创建一个填充了 C 风格函数指针和 lambda 的向量(有和没有捕获)的主要内容,如果未能解决你的问题,请参考以下文章