Я пытаюсь создать обобщенное сообщение, обрабатывающее мой код. Каждое сообщение идентифицируется целочисленным идентификатором. Поскольку все обработчики сообщений имеют одинаковое замедление, и мне нравится быстро обрабатывать каждое сообщение, я использую std::map
для подключения и нахождения соответствующего обработчика сообщений для указанных c идентификаторов сообщений. Затем я вызываю этот обработчик и передаю ему сообщение . Несколько было сделать это, и вот пример:
const std::map<int, void(*)(void*)> g_handlers = {
{1, h1},
{2, h2}
};
...
// message
int message_id = 2;
int data = 3;
// handle message
g_handlers[message_id](&data);
Но есть несколько больших ограничений для этого метода:
- Поскольку существуют разные сообщения, нам нужно обобщите их, передав их как
void*
параметр. Таким образом, каждый синтаксис обработчика сообщений будет void (*)(void*)
, и тогда мы сможем использовать его в качестве значения map. - Нет проверки типа для этого сообщения. Если кто-то неправильно добавил обработчик сообщения с идентификатором сообщения 1 для идентификатора сообщения 2, мы не сможем быстро найти эту ошибку.
Я хотел попробовать что-то новое, поэтому я пытался найти способ решить эти проблемы. проблемы, и я наконец достиг рабочего кода. Вот код:
class handler_base {
public:
template <typename U>
void operator()(U* arg) {
run(arg, typeid(U));
}
private:
virtual void run(void* arg, const std::type_info& info) {}
};
template<typename T>
class handler : public handler_base {
public:
using type = T;
handler(void (*f)(T*)) :func(f) {
}
private:
void run(void* arg, const std::type_info& info) {
assert(info.hash_code() == typeid(T).hash_code());
func(static_cast<T*>(arg));
}
void (*func)(T*);
};
int main()
{
// 2 different types of handlers
handler h1(+[](double* v){ std::cout << "double called " << *v << "\n"; });
handler h2(+[](int* v){ std::cout << "int called " << *v << "\n"; });
const std::map<int, handler_base&> myhandler = {
{1, h1},
{2, h2}
};
double d = 1.5;
int i = 3;
myhandler.at(1)(&d);
//myhandler.at(1)(&i); // Error: failed assert due to type check
//myhandler.at(2)(&d); // Error: failed assert due to type check
myhandler.at(2)(&i);
}
Теперь вот мой вопрос:
- Используется ли
&
в качестве значения карты, допустимого, когда карта const
? Я знаю, что это не так, когда сама карта не const
, но мне интересно, правильно ли она в этом случае или нет. - Есть ли какой-нибудь более простой способ сделать это? предоставление другого синтаксиса обработчика сообщений обратного вызова с использованием одного контейнера с проверкой типа?
- Что вы думаете об этой идее в целом? Это хорошая идея, чтобы добавить эту сложность для проверки типов и гетерогенных обратных вызовов? Лично я всегда go для этого правила ", простота - лучший ", и я обычно выбираю первый подход (используя обобщенный
void(*)(void*)
для обратного вызова), но мне нравится знать, что вы об этом думаете.