#c
#c
Вопрос:
Я пытаюсь реализовать общий класс обратного вызова Messenger. По сути, это сопоставление строки с вектором общих функций-членов.
std::map<Message, std::vector<std::function<void()>>> _receivers;
Класс имеет статические функции, которые в основном позволяют вам регистрировать сообщение enum для функции-члена следующим образом:
Messenger::GetInstance()->RegisterObserver(Message::QUIT, std::bind(amp;System::OnQuit, this));
Затем всякий раз, когда сообщение передается куда-либо, происходит обратный вызов.
Messenger::GetInstance()->Broadcast(Message::QUIT);
Реализация заключается в следующем.
class Messenger
{
public:
template <typename Receiver>
void RegisterObserver(Message msg, Receiveramp;amp; receiver)
{
_receivers[msg].push_back(std::forward<Receiver>(receiver));
}
static Messenger* GetInstance();
void Broadcast(Message msg) const
{
for (const autoamp; obs : _receivers.at(msg)) obs();
}
void Broadcast(Message msg, void* param) const;
{
for (const autoamp; obs : _receivers.at(msg)) obs(param); // Does NOT work
}
~Messenger();
private:
Messenger() { };
std::map<Message, std::vector<std::function<void()>>> _receivers;
static Messenger* _instance;
};
Реализация хорошо работает без каких-либо параметров.
Теперь мне также нужно, чтобы это работало с параметром void *, чтобы я мог также передавать что-либо вместе с трансляцией, если мне нужно, чтобы оно вызывалось при обратном вызове.
Это то, чего я хочу достичь.
Messenger::GetInstance()->Broadcast(Message::QUIT, *param);
Любой совет или решение очень ценятся. Это поможет мне сохранить мой дизайн в здравом уме.
Я попытался изменить map на —
std::map<Message, std::list<std::function<void(void*)>>> _receivers;
а затем изменить подписи вызовов на void CallbackName(void* param). Однако я получаю сообщение об ошибке
error C2064: term does not evaluate to a function taking 1 arguments
Вероятно, из-за этого:
Messenger::GetInstance()->RegisterObserver(Message::QUIT, std::bind(amp;System::OnQuit, this));
Комментарии:
1. Вы хотя бы попытались адаптировать сигнатуру своей функции для обработки этого параметра? Где вы застряли, делая это?
2. Вы можете создать 2
std::map
, один дляstd::function<void()>
, а другой дляstd::function<void(void*)>
.3. Mat: Попробовал, что получил ошибку, упомянутую выше.
4. Jarod42: Как в этом случае будет работать функция Register ?
5. Какие параметры
System::OnQuit()
принимает в том случае, когда он выдает ошибку?
Ответ №1:
Вы можете создать 2 карты и использовать 2 метода регистрации. Если вам нужно то же имя, вы можете использовать SFINAE следующим образом: Живой пример
class Messenger
{
public:
template <typename Receiver>
auto RegisterObserver(Message msg, Receiveramp;amp; receiver) -> decltype(receiver(), void())
{
_receivers0[msg].push_back(std::forward<Receiver>(receiver));
}
template <typename Receiver>
auto RegisterObserver(Message msg, Receiveramp;amp; receiver) -> decltype(receiver(nullptr), void())
{
_receivers1[msg].push_back(std::forward<Receiver>(receiver));
}
// Others methods
private:
std::map<Message, std::vector<std::function<void()>>> _receivers0;
std::map<Message, std::vector<std::function<void(void*)>>> _receivers1;
};
Комментарии:
1. Фантастический Джарод42. Это абсолютно то, чего я хотел достичь. 🙂 Если вы можете добавить методы для отмены регистрации наблюдателей и для 2 карт, это было бы идеально!