Ответы пользователя по тегу C++
  • Одна сигнатура и несколько возвращаемых типов: как победить "двусмысленность"?

    @johnslowpoke Автор вопроса
    Получилось вот это...

    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>();


    Даже не знаю, что хуже :/
    Ответ написан