传递和存储lambda函数作为回调

Gra*_*pes 20 c++ lambda callback c++11

我想知道这是否是一种可接受的写回调的方法:

存储回调:

struct EventHolder {
    std::function<void()> Callback;
    EventTypes::EventType Type;
};
std::vector<Events::EventHolder> EventCallbacks;
Run Code Online (Sandbox Code Playgroud)

方法定义:

void On(EventType OnEventType,std::function<void()>&& Callback)
{
    Events::EventHolder NewEvent;
    NewEvent.Callback=std::move(Callback);
    NewEvent.Type=OnEventType;
    EventCallbacks.push_back(std::move(NewEvent));
}
Run Code Online (Sandbox Code Playgroud)

绑定事件:

Button->On(EventType::Click,[]{
    // ... callback body
});
Run Code Online (Sandbox Code Playgroud)

我最大的问题是关于通过值传递回调.这是一种有效的方法吗?

Age*_*ien 12

这是存储事件处理程序的完美有效方法.

但是,我想指出一些关于添加回调函数签名的细节.你担心通过值和引用传递它.在您的示例中,您目前拥有:

void On(EventType OnEventType,std::function<void()>&& Callback)
Run Code Online (Sandbox Code Playgroud)

这很好,只要你只将它绑定到右值.但是,除非您有特殊原因要禁止它,否则我建议您始终使用一个方法,该方法按值或左值引用接受参数,并在必要时添加右值参考版本作为补充.

没有一个采用左值引用的方法意味着你的代码目前无法编译,因为:

std::function<void()> func([](){/*something clever*/});
// Do something necessary with func, perhaps logging or debug prints.
Button->On(EventType::Click, func);
Run Code Online (Sandbox Code Playgroud)

为简单起见,无论何时选择如何传递值,您都可以简单地遵循以下准则:

  • 如果您需要副本或打算修改发送的值,而不想更改传递的实际对象:按值传递.
  • 如果您打算修改发送的值,并希望这些更改影响传递的实际对象:按引用传递.
  • 如果你不想改变传递的对象,但相信避免复制是有益的:传递const引用.
  • 如果您通过值,引用或const引用获取参数,并且相信使用输入参数是临时的知识可以实现有价值的优化:还允许通过右值引用.