Страницы

Поиск по вопросам

четверг, 9 января 2020 г.

Структура данных для хранения callbackов

#cpp #cpp17


Мне нужна структура данных, которая каждой строке будет ставить в соответствие некоторую
callback-функцию. Эта структура будет инициализироваться извне класса с помощью лямбд.
Какую структуру данных лучше использовать, если сигнатуры функций могут быть разными?

Нужно такое поведение:

map["gui_ok_button"] = [&](){
   data.apply();
};
map["gui_close_button"] = [&](int close_code){
   data.close(close_code);
};

    


Ответы

Ответ 1



Новые возможности Си++17 вам помогут. Могу предложить реализация на std::variant: #include #include #include #include // здесь должны быть перечислены варианты // всех сигнатур using Callback = std::variant < std::function , std::function , std::function >; using CallbackMap = std::map; Далее главная идея решения, функция вызова: // Эта перегрузка нужна для обработки неверных вызовов // статическая проверка пока не приходит на ум. template void DoCall(F&&, A&&...) { throw std::bad_variant_access(); } // Нужно для каждой варианта сигнатуры определить перегрузку для проброски // аргументов. Выглядит коряво, тут можно автоматизировать. void DoCall(std::function & f) { f(); } void DoCall(std::function & f, int arg) { f(arg); } void DoCall(std::function & f, const std::string & arg) { f(arg); } // Собственно вызов калбека template void Dispatch(const Callback & callback, A&& ...args) { // здесь лямбда нужна чтобы захватить args и передать в DoCall, // все из-за того что std::visit не предусматривает проброс // аргументов в посетителя (здесь в нашу лямбду) std::visit ( [&args...](auto && func) -> void { DoCall(func, std::forward(args)...); } , callback ); } Использовать это вот так как-то: void TestCallbackMap() { auto cm = CallbackMap(); cm["foo"] = [](void) -> void { std::cout << "call: foo" << std::endl; }; cm["bar"] = [](int arg) -> void { std::cout << "call: bar " << arg << std::endl; }; cm["baz"] = [](const std::string & msg) -> void { std::cout << "call: baz " << msg << std::endl; }; Dispatch(cm["baz"], std::string("hello world")); }

Комментариев нет:

Отправить комментарий