【发布时间】:2017-11-12 13:38:51
【问题描述】:
我目前正在尝试为我的游戏引擎实现一个信使系统。它使用以下形式的函数回调:
typedef std::function<void(const Message &)> Callback;
它维护一个消息列表:
mutable std::vector<std::unique_ptr<Message>> messageList;
还有一个签名的回调字典:
mutable std::map<std::string, std::vector<Callback>> callbackDictionary;
用于将所有回调“绑定”到特定的消息类型。调用回调函数时,会传递相应的消息。到目前为止一切顺利。
为了更好地理解,这里是 subscribe 方法,它允许用户添加一个函数方法,该方法为订阅类型的每条消息调用。
void Messenger::Subscribe(Message::Type type, Callback callbackFunction)
const
{
callbackDictionary[type].push_back(callbackFunction);
}
这里有一个例子说明它是如何使用的(通过可点击组件类)
messageBus.Subscribe("Message/Click", [this](const Message & message) {this->OnClick(static_cast<const ClickMessage &>(message)); });
现在我的问题:
我想实现一个取消订阅方法,该方法在字典的向量中找到一个函数/方法并将其删除。请注意,该函数可以订阅一种以上的消息类型。我在想这样的事情:
void Messenger::UnSubscribe(Callback callbackFunction)
{
for (auto & pair : callbackDictionary)
{
auto & functionList = pair.second;
for (auto function : functionList)
{
if (function == callbackFunction)
functionList.erase(std::remove(functionList.begin(), functionList.end(), function), functionList.end());
// I am aware of issues that may appear from looping deleting while looping
}
}
}
但是,对于函数对象,比较运算符 (==) 似乎未定义。我想不出一个简单的方法来解决这个问题。因此,任何想法都非常受欢迎。我只是想从经验中避免某种 id 系统原因,这可能是一项繁琐的管理工作。尤其是当各种函数和成员可以在整个程序中随处添加时。
【问题讨论】:
-
像stackoverflow.com/a/18039824/451600 这样的解决方案会起作用吗?
-
什么时候回调在概念上等同于 unsubscribe()'ing ?请注意,闭包对象(即 lambda 表达式的结果)具有唯一的类型 ...
-
@CaptainGiraffe 甚至假设这是 OP 真正想要的,它仅适用于函数指针和无捕获 lambda(或任何你知道的前期类型)......
-
你考虑过使用Boost Signals吗?
-
@AdrianKoch "callables" 在 C++ 中没有对它们进行自然相等操作。
std::function是一个 callable (嗯,可复制的 callables),而不是你认为它是建模的任何东西。其次,您的系统似乎需要将一条消息传递给回调(或某种动态或不安全的强制转换),这似乎不是最理想的。第三,如果你注册了一个回调,然后回调中引用的对象的生命周期结束了怎么办?
标签: c++ dictionary vector std-function