Рад за них. И тридцати лет не прошло, как в Цэ появились кложуры!
Причём поистине в С++-way. =) Что на самом деле делает эта конструкция - она создаёт класс с переопределенным operator() с аргументами и телом данными в выражении. Далее в этом классе заводятся поля упомянутые в квадратных скобках. Здесь же создаётся экземпляр этого класса в конструктор которого передаются внешние переменные упомянутые в квадратных скобках или по значению (т.е. просто копируются), или по ссылке (если стоит & которую я поставил, тогда время существования переменной на которую идёт ссылка нуждается в прямых руках, ибо никакого "захвата" внешнего контекста не происходит, происходит лишь копирования или ссылки на внешние переменные. в этом смысле замыкание мягко говоря неполноценное.). Т.е. на самом деле это синтаксический сахарок над созданием класса-функтора в экземпляр которого передаётся ссылка на переменную c, а далее экземпляр работает как обычный функтор и ничем иным на самом деле и не является.
Одно из последствий этого подхода - все С++-лямбды являются объектами РАЗНЫХ классов, даже если они абсолютно идиентичны или совпадают по сигнатурам. Поэтому это еще не делегат. (вообще на самом деле для реализации делегатов именно С++-лямбды не нужны, std::bind так и заводит - функтор, типа выводимого из аргументов шаблона)
Делегатом оно становится, когда этот функтор (произвольного типа) упрятывается за "оболочкой" конкретного типа, позволяющей копировать и вызывать делегаты между собой ориентируясь только на сигнатуру метода, без фиксации на том что там за класс и объект внутри.
Тут уже вступает в роль std::function.
В gnu-std реализация std::function для выполнения этой цели производит классический для С++ приём "type erasure". При этом возникает вот какой подвох. Сам класс std::function имеет фиксированный размер и внутреннее обустройство (ну что логично, иначе бы копирование между экземплярами не работало), поэтому вышеупомянутый функтор он вынужден "прятать" в динамическую память. Действительно размер и внутреннее обустройство функтора-заглушки неизвестно, поэтому std::function в код-перемычке в момент инициализации создаёт промежуточный класс-агрегатор для type-erasure который размещается в куче по new и в него уже "загружается" содержимое функтора копированием.
Таким образом то что в грёбанном Дельфи было внутри структурой из двух указателей, легко копируемых и легко инициализируемых, в С++ в gnu-std превращается в момент инициализации в лазание в динамическую память и в косвенную двойную индирекцию при инвокации. (правда тут следует заметить, что std::function умеет намного более, чем делегат, поэтому сравнивать немного некорректно. там где можно обойтись делегатами делегат бы хорошенько выиграл в ряде моментов, но std::function умеет много больше)
В момент инвокации уже всё не так плохо. Можно даже сказать что всё хорошо. Хотя глядя в асмовыхлоп такого я бы не сказал заранее не видя результатов. Но тут уже вопросы современных процессоров. new же, как понимаете, никакой оптимизатор не "вычистит" никогда.
Так что не всё так безоблачно с оптимизациями и так далее.
Ну а синтаксис, сравните как могло бы быть и как есть:
std::function<void(int,char*,float)> functor = std::bind( &MyClass::MyMethod, &obj, std::_1, std::_2, std::_3 );
// vs (гипотетически)
void (class *delegate)(int, char*,float) = obj.MyMethod; // class говорит что это не указатель на функцию, а делегат.
// более того без всяких изменений в std можно было бы писать:
std::function<void(int,char*,float)> functor = obj.MyMethod;
// просто потому что делегат как и указатель на функцию тоже внешне для шаблонного когда есть функтор, сущность у которой есть operator()
Дело вкуса? Дело оптимизатора?
По моему тут двух мнений быть не может. Если можно упростить и можно ускорить, то если бы насчёт какого то другого языка можно было бы поспорить, то с С++ - нет. С++ всегда шёл под флагом "всё заради эффективности и красоты кода".
Другое дело да, что есть суровая реальность и с ней приходится мирится. Стандартизаторы уже чего только в С++11 не понаввели (если для вас лямбды было новостью, то некоторые вещи просто шокируют), ради эффективности например даже перегрузку r-value-reference (!). Но над делегатами похоже никто вообще не заморачивается. А жаль.