Получилось вот это...
enum class Event {
CREATE, TERMINATE, TIMEOUT, PARTYTIME
};
static std::map<Event, std::function<void()>> callbackMap {
{ Event::CREATE, []{ std::cout << "CREATE\n"; } },
{ Event::TERMINATE, []{ std::cout << "TERMINATE\n"; } },
{ Event::TIMEOUT, []{ std::cout << "TIMEOUT\n"; } },
{ Event::PARTYTIME, []{ std::cout << "PARTYTIME\n"; } },
};
struct App {
struct Callback {
using Create = int(*)(void *);
using Terminate = void(*)(void *);
using Timeout = void(*)(void *); // идентичен с Terminate
using Partytime = const char *(*)(int, void *);
};
template <typename TCallback, Event TEvent>
static TCallback getCallback();
};
template <>
App::Callback::Create App::getCallback<App::Callback::Create, Event::CREATE>() {
return [](void *) { callbackMap[Event::CREATE](); return 42; };
}
template <>
App::Callback::Terminate App::getCallback <App::Callback::Terminate, Event::TERMINATE>() {
return [](void *) { callbackMap[Event::TERMINATE](); };
}
template <>
App::Callback::Timeout App::getCallback <App::Callback::Timeout, Event::TIMEOUT>() {
return [](void *) { callbackMap[Event::TIMEOUT](); };
}
template <>
App::Callback::Partytime App::getCallback <App::Callback::Partytime, Event::PARTYTIME>() {
return [](int, void *) -> const char * { callbackMap[Event::PARTYTIME](); return nullptr; };
}
// костыльная функция, роль которой в реальном коде выполняет ОС
template <typename T>
void caller(T callback) {
callback(nullptr);
}
template <>
void caller(App::Callback::Partytime callback) {
callback(0, nullptr);
}
int main() {
auto create = App::getCallback<App::Callback::Create, Event::CREATE>();
auto terminate = App::getCallback<App::Callback::Terminate, Event::TERMINATE>();
auto timeout = App::getCallback<App::Callback::Timeout, Event::TIMEOUT>();
auto partytime = App::getCallback<App::Callback::Partytime, Event::PARTYTIME>();
// ОС дергает колбэки
caller(create);
caller(terminate);
caller(timeout);
caller(partytime);
}
Из-за перегруженности кода теряется смысл всей затеи, проще тогда уж без лямбд и блекджека...
UPD: менее нагруженный вариант, но придется держать в уме особые правила вызова для terminate и timeout
...
template <typename TCallback>
static TCallback getCallback();
template <typename TCallback, Event TEvent>
static TCallback getCallback();
...
auto create = App::getCallback<App::Callback::Create>();
auto terminate = App::getCallback<App::Callback::Terminate, Event::TERMINATE>();
auto timeout = App::getCallback<App::Callback::Timeout, Event::TIMEOUT>();
auto partytime = App::getCallback<App::Callback::Partytime>();
Даже не знаю, что хуже :/