если сильно надо
Нет, это вопрос чисто умозрительный и совершенно не срочный.
Я предложил подумать.
Можно ввести одно ограничение, не вызывающее больших проблем у пользователей, значительно упрощающее задачу: в .NET принято (но не обязательно) прототипы делегатов и обработчиков задавать следующим образом:
void Handler(object sender, EventArgs arg)
Во-первых, обработчик ничего не возвращает, так как внутри коллекции обработчиков события эти результаты никак не выудить. Во-вторых, у него два аргумента: объект-издатель, посылающий уведомление, и объект класса EventArgs, в который упаковывается вся прочая информация. В .NET рекомендуется, чтобы классы-аргументов обработчиков были производными от EventArgs (хотя тоже не обязательно).
В C++ для полной гибкости следовало бы определить функцию или метод типа:
void (*)(void *sender, void *arg)
Однако такое решение полностью лишает нас возможности контролировать типы параметров обработчика. Все проблемы крупной программы перекладывают с "плеч" компилятора на плечи программиста. Такое решение + потенциальный источник ошибок времени исполнения.
Можно было бы воспользоваться шаблонами, но здесь возникают проблемы с определением "делегата". Конструкции вида
template<class Publisher, class EventArg>
typedef void (*Delegate)(Publisher *sender, EventArg *arg);
запрещены. Применение шаблонов к typedef появится только в будущем стандарте языка (это уже запланировано).
С другой стороны, вышеприведённое определение применимо лишь к функциям, для методов классов необходимо иное:
void (Class::*Delegate)(Publisher *sender, EventArg *arg)
В любом случае определённость хотя бы с количеством параметров и семантическая определённость их типов (каков смысл типов параметров) снимает проблему создания множества перегруженных операторов для произвольных наборов параметров.