Делегаты на C++
От: Александр Шаргин Россия RSDN.ru
Дата: 30.04.03 05:55
Оценка: 517 (18)
Статья :
Делегаты на C++
Автор(ы): Александр Шаргин
Дата: 19.03.2003
Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках "чистого" C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.


Авторы :
Александр Шаргин

Аннотация :
Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках "чистого" C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
наследование операторов
От: yaroslav_v http://yaroslav-v.chat.ru
Дата: 01.05.03 05:55
Оценка:
>Дело в том, что в языке C++ операторы не наследуются.
Это не верно по крайней мере для MSVC++.
Более того этот метод используется при написании функтора из библиотеки Loki
http://fara.cs.uni-potsdam.de/~kaufmann/?page=lokiport (файл Functor.h),
см. также http://www.geocities.com/rani_sharoni/LokiPort.html (VC7) и конечно
оригинал http://moderncppdesign.com/

#include <stdio.h>
int main()
{
struct base
{
void operator()(int x)
{
printf("void base::operator()(%d)\n",x);
}
};
struct derived : base
{
};
derived()(5);
return 0;
}
Велосипед
От: WolfHound  
Дата: 18.06.03 18:04
Оценка: +2
Здравствуйте, Александр Шаргин, Вы писали:

сабж.
см boost\signal
... << RSDN@Home 1.0 beta 6a >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Велосипед
От: Alexander Shargin Россия RSDN.ru
Дата: 18.06.03 18:20
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Александр Шаргин, Вы писали:


WH>сабж.

WH>см boost\signal

Ага. И не только. Кто только это не реализовывал.

Но.
а) Статья писалась в учебных целях, чтобы показать на не очень навороченном примере как делаются такие вещи.
б) Код писался с прицелом на VC (в т. ч. 6.0), который с boost'ом не дружит.
в) Мне просто было интересно дойти до этого самому и получить удовольствие от процесса.
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
Re[2]: Велосипед
От: WolfHound  
Дата: 19.06.03 03:56
Оценка:
Здравствуйте, Alexander Shargin, Вы писали:

AS>б) Код писался с прицелом на VC (в т. ч. 6.0), который с boost'ом не дружит.

Уверен?
Preferred syntax 
GNU C++ 2.95.x, 3.0.x, 3.1.x

Comeau C++ 4.2.45.2

SGI MIPSpro 7.3.0

Intel C++ 5.0, 6.0

Compaq's cxx 6.2
 Any compiler supporting the preferred syntax

Portable syntax 

Microsoft Visual C++ 6.0, 7.0

Borland C++ 5.5.1

Sun WorkShop 6 update 2 C++ 5.3

Metrowerks CodeWarrior 8.1
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Велосипед
От: Alexander Shargin Россия RSDN.ru
Дата: 19.06.03 07:02
Оценка:
Здравствуйте, WolfHound, Вы писали:

AS>>б) Код писался с прицелом на VC (в т. ч. 6.0), который с boost'ом не дружит.

WH>Уверен?

Возможно, с тех пор ситуация изменилась. А возможно, я заблуждался с самого начала. В чистом виде boost не компилируется на VC6 и это факт, но не исключено, что его удалось портировать примерно так же, как я это делал в своей статье.

Вопрос, на самом деле, достаточно интересный. Если будет свободная минутка, я проверю это и напишу сюда.
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
Re: Велосипед
От: MaximE Великобритания  
Дата: 19.06.03 07:14
Оценка: 2 (1)
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Александр Шаргин, Вы писали:


WH>сабж.

WH>см boost\signal

Еще есть Libsigc++, но она больно уж под Unix заточена.
Re[2]: Велосипед
От: Alexmoon Украина  
Дата: 19.06.03 08:35
Оценка:
Здравствуйте, Alexander Shargin, Вы писали:

AS>а) Статья писалась в учебных целях, чтобы показать на не очень навороченном примере как делаются такие вещи.

AS>б) Код писался с прицелом на VC (в т. ч. 6.0), который с boost'ом не дружит.
AS>в) Мне просто было интересно дойти до этого самому и получить удовольствие от процесса.

От меня тебе огромное спасибо Александр. Мне твоя очень вовремя попалась, как раз когда я для своего COM сервера пытался реализовать обратную связь с клиентом, т.е. поддержку событийных интерфейсов. Я как раз размышлял об эффективном и с возможностью повторного использования кода реализации интерфейса IMyEvent и прочитав твою статью я практически пришел к моментальному выводу. Пишем объект делегат, который регестрируется под объектмом event slot, идея написания которого пришла после прочтения статьи "Обработка событий в С++", которая обитает здесь же. Объект eventSlot and EventRaiser я конечно несколько по своему модернизировал, а вот твой делегат мне понравился. EventRaiser реализует сервер, а eventSlot клиент и после написания интерфейсов это все уже почти прекрасно работает.

Единственное но, в твоем делегате была скрытая утечка памяти, которую я уже устранил и хочу тебе вернуть конечный полностью работоспособный результат твоей работы. Куда положить файлы?
Re[3]: Велосипед
От: Alexander Shargin Россия RSDN.ru
Дата: 19.06.03 08:45
Оценка:
Здравствуйте, Alexmoon, Вы писали:

A>Здравствуйте, Alexander Shargin, Вы писали:


AS>>а) Статья писалась в учебных целях, чтобы показать на не очень навороченном примере как делаются такие вещи.

AS>>б) Код писался с прицелом на VC (в т. ч. 6.0), который с boost'ом не дружит.
AS>>в) Мне просто было интересно дойти до этого самому и получить удовольствие от процесса.

A>От меня тебе огромное спасибо Александр. Мне твоя очень вовремя попалась, как раз когда я для своего COM сервера пытался реализовать обратную связь с клиентом, т.е. поддержку событийных интерфейсов. Я как раз размышлял об эффективном и с возможностью повторного использования кода реализации интерфейса IMyEvent и прочитав твою статью я практически пришел к моментальному выводу. Пишем объект делегат, который регестрируется под объектмом event slot, идея написания которого пришла после прочтения статьи "Обработка событий в С++", которая обитает здесь же. Объект eventSlot and EventRaiser я конечно несколько по своему модернизировал, а вот твой делегат мне понравился. EventRaiser реализует сервер, а eventSlot клиент и после написания интерфейсов это все уже почти прекрасно работает.


A>Единственное но, в твоем делегате была скрытая утечка памяти, которую я уже устранил и хочу тебе вернуть конечный полностью работоспособный результат твоей работы. Куда положить файлы?


На сайт попала не самая последняя версия статьи. В ближайшее время я буду обновлять её. Заодно исправлю и эту проблему. Код можно прислать мне по email: rudankort@rsdn.ru. Спасибо заранее!
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
Re[4]: Велосипед
От: Alexmoon Украина  
Дата: 19.06.03 08:57
Оценка:
Здравствуйте, Alexander Shargin, Вы писали:

AS>На сайт попала не самая последняя версия статьи. В ближайшее время я буду обновлять её. Заодно исправлю и эту проблему. Код можно прислать мне по email: rudankort@rsdn.ru. Спасибо заранее!


Выслал файлы на email.
Re[4]: Велосипед
От: WolfHound  
Дата: 19.06.03 09:04
Оценка:
Здравствуйте, Alexander Shargin, Вы писали:

AS>Возможно, с тех пор ситуация изменилась. А возможно, я заблуждался с самого начала. В чистом виде boost не компилируется на VC6 и это факт, но не исключено, что его удалось портировать примерно так же, как я это делал в своей статье.

boost на 100% вроде не компилит ни один компилятор, но частично он прекрасно компилируется и работает на очень многих. Какие части и чем компилятся надо смотреть в документации к конкретной части.
... << RSDN@Home 1.0 beta 6a >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: наследование операторов
От: Lorenzo_LAMAS  
Дата: 19.06.03 09:35
Оценка:
Здравствуйте, yaroslav_v, Вы писали:

>>Дело в том, что в языке C++ операторы не наследуются.

_>Это не верно по крайней мере для MSVC++.
Это неверно не только для MSVC.
Of course, the code must be complete enough to compile and link.
Re[3]: Велосипед
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 19.06.03 09:47
Оценка:
Здравствуйте, Alexmoon, Вы писали:

A>...как раз когда я для своего COM сервера пытался реализовать обратную связь с клиентом, т.е. поддержку событийных интерфейсов.


хм, кстати о велосипедах, а IConnectionPoint -то чем не угодил?
Re[4]: Велосипед
От: Alexmoon Украина  
Дата: 19.06.03 10:00
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>хм, кстати о велосипедах, а IConnectionPoint -то чем не угодил?


Кто сказал, что он не угодил. Что такое IConnectionPoint? Это интерфейс регистрации на сервере интерефейсов IMyEvent.
Вот о реализации последних я и рассказывал.
Re[5]: Велосипед
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 19.06.03 10:43
Оценка:
Здравствуйте, Alexmoon, Вы писали:

OE>>хм, кстати о велосипедах, а IConnectionPoint -то чем не угодил?


A>Кто сказал, что он не угодил. Что такое IConnectionPoint? Это интерфейс регистрации на сервере интерефейсов IMyEvent.

A>Вот о реализации последних я и рассказывал.

в сервере делаем стандартную реализацию

class CProxy_IххххххххEvents : public IConnectionPointImpl<...>
{
public:
     HRESULT Fire_xxxxxxxxx()

  //и т.д. с перебором точек соединения и вызовом для каждой pDispatch->Invoke


клиент подписывается через Advise и имеет информацию обо всех событиях.

я таки пытаюсь понять где тут место для самодельных слотов и делегатов и почему мне это не разу не понадобилось, может я много чего потерял
Re[2]: наследование операторов
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 19.06.03 10:52
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

хъ

Это частично не верно.
Re[6]: Велосипед
От: Alexmoon Украина  
Дата: 19.06.03 11:00
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>клиент подписывается через Advise и имеет информацию обо всех событиях.


OE>я таки пытаюсь понять где тут место для самодельных слотов и делегатов и почему мне это не разу не понадобилось, может я много чего потерял


да ничего ты не потерял. просто у меня есть свои мысли и идеи по поводу реализации подобных вещей и я просто упомянул область, где мне пригодится делегат, а не выставлял на обсуждение собственный вариант реализации.
можно обойтись и без него. а я хочу с ним ). И по эффективности будет тоже самое, но хочу попробовать альтернативный вариант.
Тяжело в форуме объяснить все свои мысли и поэтому я вернусь к обсуждению этого только после окончания работы.
Re[3]: наследование операторов
От: Lorenzo_LAMAS  
Дата: 19.06.03 11:09
Оценка:
AS>Это частично не верно.

Ну что ж, давай пример
Of course, the code must be complete enough to compile and link.
Re[5]: Велосипед
От: Alexander Shargin Россия RSDN.ru
Дата: 19.06.03 11:10
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Alexander Shargin, Вы писали:


AS>>Возможно, с тех пор ситуация изменилась. А возможно, я заблуждался с самого начала. В чистом виде boost не компилируется на VC6 и это факт, но не исключено, что его удалось портировать примерно так же, как я это делал в своей статье.

WH>boost на 100% вроде не компилит ни один компилятор, но частично он прекрасно компилируется и работает на очень многих. Какие части и чем компилятся надо смотреть в документации к конкретной части.

Судя по информации здесь: http://www.boost.org/doc/html/ch04s02.html, Visual C++ не понимает сигналы с "нормальным" синтаксисом, но понимает их с "портабельным" синтаксисом. С чем себя и всех и поздравляю.

В портабельном синтаксисе, в отличае от нормального, количество параметров необходимо указывать в имени класса: signal0, а не signal.
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
Re[3]: Велосипед
От: Юнусов Булат Россия  
Дата: 19.06.03 12:01
Оценка:
Здравствуйте, WolfHound, Вы писали:

Тогда в бусте официально вроде не было сигналов.

У меня все ходы записаны
Делегаты на C++
Автор: Александр Шаргин
The RSDN Group
Опубликовано: 28.01.2002
Версия текста: 1.0



October 10, 2002 - Version 1.29.0
Signals Library added - Managed signals & slots callback implementation, from Doug Gregor.
Re[2]: Велосипед
От: jazzer Россия Skype: enerjazzer
Дата: 19.06.03 14:59
Оценка: +1
Здравствуйте, Alexander Shargin, Вы писали:

AS>в) Мне просто было интересно дойти до этого самому и получить удовольствие от процесса.


наш человек!
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: наследование операторов
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 20.06.03 03:29
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

[]

L_L>Ну что ж, давай пример


operator=
Re[5]: наследование операторов
От: Lorenzo_LAMAS  
Дата: 20.06.03 06:57
Оценка:
AS>operator=

Нет.

Он наследуется, но так как в производном классе компилятор неявно определяет оператор присваивания, то он hides оператор из базы.
Of course, the code must be complete enough to compile and link.
Re[6]: наследование операторов
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 20.06.03 09:17
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

[]

Другими словами — не наследуется.
Re[2]: Велосипед
От: eluka Швеция  
Дата: 05.08.03 10:10
Оценка: 1 (1)
Здравствуйте, MaximE, Вы писали:

ME>Здравствуйте, WolfHound, Вы писали:


WH>>Здравствуйте, Александр Шаргин, Вы писали:


WH>>сабж.

WH>>см boost\signal

ME>Еще есть Libsigc++, но она больно уж под Unix заточена.


А еще есть Sigslot. Она в отличии от boost::signal thread-safe.
Re[7]: наследование операторов
От: Аноним  
Дата: 28.08.03 12:21
Оценка:
Здравствуйте, Alexey Shirshov, Вы писали:

AS>Другими словами — не наследуется.


Наследуется, но его имя скрыто.

Вот конструктор — тот не наследуется.
Re: Отчего boost такой вычурный?
От: Gregory Россия ICQ 300403361
Дата: 29.08.03 09:18
Оценка:
Здравствуйте, Александр Шаргин, Вы писали:

АШ>Статья :

АШ>Делегаты на C++

Прочитал статью. Заинтересовался идеей. Реализация, приводимая в статье, конечно оставляет желать лучшего, но дело не в этом.
В одном из постов по данной теме упоминался boost::signal. Скачал boost. Попробовал компильнуть тест для boost::signal посредством VC6 (VC7 пробовать не стал). VC6 сказал что у него INTERNAL COMPILER ERROR, и посоветовал обратиться куда следует. Обращаться не стал, искать баг в boost и в вижуале тоже (пусть это останеться на их совести). В boost нашел boost::function, тест для которого VC6 скомпилил. Для моих целей boost::function вполне бы подошел, т.к. мне не требуется одним махом вызывать кучу функций, но...
в этом собственно и состоит вопрос:

В процессе выяснения "зачем они тут так крепят" обнаружил что boost::function реализован очень вычурно. Если взять код из статьи и довести его до ума, или прописать нечто свое (что я и сделал), то можно получить теже самые результаты более простыми способами без алокаторов, итераторов, any_pointer, useless_clear_type и прочих наворотов. Зачем это все нужно? Для переносимости кода? По-моему это все равно, что оптический прицел к открывалке для пива приделать.

И еще один впрос. Если вызвать operator() делегата, который вызывает несколько функций, возвращающих скажем int, то что вернет оператор?
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re[2]: Отчего boost такой вычурный?
От: MaximE Великобритания  
Дата: 29.08.03 10:03
Оценка:
Здравствуйте, Gregory, Вы писали:

[]

G>В процессе выяснения "зачем они тут так крепят" обнаружил что boost::function реализован очень вычурно. Если взять код из статьи и довести его до ума, или прописать нечто свое (что я и сделал), то можно получить теже самые результаты более простыми способами без алокаторов, итераторов, any_pointer, useless_clear_type и прочих наворотов. Зачем это все нужно? Для переносимости кода? По-моему это все равно, что оптический прицел к открывалке для пива приделать.


Признаюсь, статью на RSDN я не читал, только просмотрел.

boost::function<> может принимать не только укзатели на функции и на функции-члены, но и bind и labda выражения. Насколько я понял, CDelegate из статьи этого сделать не могут.

G>И еще один впрос. Если вызвать operator() делегата, который вызывает несколько функций, возвращающих скажем int, то что вернет оператор?


В доках boost::signals все подробно написано:

Signal Return Values (Advanced)
Just as slots can receive arguments, they can also return values. These values can then be returned back to the caller of the signal through a combiner. The combiner is a mechanism that can take the results of calling slots (there many be no results or a hundred; we don't know until the program runs) and coalesces them into a single result to be returned to the caller. The single result is often a simple function of the results of the slot calls: the result of the last slot call, the maximum value returned by any slot, or a container of all of the results are some possibilities.

Re[3]: Отчего boost такой вычурный?
От: MaximE Великобритания  
Дата: 29.08.03 10:09
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Здравствуйте, Gregory, Вы писали:


ME>[]


G>>В процессе выяснения "зачем они тут так крепят" обнаружил что boost::function реализован очень вычурно. Если взять код из статьи и довести его до ума, или прописать нечто свое (что я и сделал), то можно получить теже самые результаты более простыми способами без алокаторов, итераторов, any_pointer, useless_clear_type и прочих наворотов. Зачем это все нужно? Для переносимости кода? По-моему это все равно, что оптический прицел к открывалке для пива приделать.


ME>Признаюсь, статью на RSDN я не читал, только просмотрел.


ME>boost::function<> может принимать не только укзатели на функции и на функции-члены, но и bind и labda выражения. Насколько я понял, CDelegate из статьи этого сделать не могут.


Одно из важнейших преимуществ boost::function<> в том, что он может осуществлять конверсию аргументов:

Generally, any place in which a function pointer would be used to defer a call or make a callback, Boost.Function can be used instead to allow the user greater flexibility in the implementation of the target. Targets can be any 'compatible' function object (or function pointer), meaning that the arguments to the interface designated by Boost.Function can be converted to the arguments of the target function object.

Re[3]: Отчего boost такой вычурный?
От: Gregory Россия ICQ 300403361
Дата: 29.08.03 11:01
Оценка:
Здравствуйте, MaximE, Вы писали:


ME>Признаюсь, статью на RSDN я не читал, только просмотрел.


А я "прсмотрел" доку к бусту

ME>boost::function<> может принимать не только укзатели на функции и на функции-члены, но и bind и labda выражения. Насколько я понял, CDelegate из статьи этого сделать не могут.


CDelegate из статьи так или иначе инкапсулируют функцию. bind и lambda они принимать конечно не могут, равно как и как-то обрабатывать возвращаемые значения нескольких вызовов.

boost::function штука несомнено мощная. Проникся. Но вот из-за этой мощности использовать ее мне как-то не хочется. Ну не нужна мне лямбда.


Спасибо, MaximE.
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re[2]: Отчего boost такой вычурный?
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 29.08.03 11:14
Оценка:
Здравствуйте, Gregory, Вы писали:

G>И еще один впрос. Если вызвать operator() делегата, который вызывает несколько функций, возвращающих скажем int, то что вернет оператор?


На этот вопрос нет прямого ответа. Можно принять последний возвращаемый результат, можно привесить какой-нить контейнер для сбора ответов, можно прекращать обработку выозва при получении определённого результата.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re: Делегаты на C++
От: Аноним  
Дата: 19.12.06 09:45
Оценка:
Здравствуйте, Александр Шаргин, Вы писали:

Версия делегатов для VC 6.0 не компилится под VC 8.0 Хотелось бы иметь общую рабочую для обоих студий версию

------ Rebuild All started: Project: DelegatesDemo, Configuration: Debug Win32 ------
Deleting intermediate and output files for project 'DelegatesDemo', configuration 'Debug|Win32'
Compiling...
demo.cpp
d:\research\delegates\delegate_impl.h(19) : warning C4346: 'DelegateRetVal<T>::Type' : dependent name is not a type
        prefix with 'typename' to indicate a type
        d:\research\delegates\delegate_impl.h(21) : see reference to class template instantiation 'IDelegate0<TRet>' being compiled
d:\research\delegates\delegate_impl.h(19) : error C2146: syntax error : missing ';' before identifier 'Invoke'
d:\research\delegates\delegate_impl.h(19) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\research\delegates\delegate_impl.h(19) : warning C4183: 'Invoke': missing return type; assumed to be a member function returning 'int'
d:\research\delegates\delegate_impl.h(31) : warning C4346: 'DelegateRetVal<T>::Type' : dependent name is not a type
        prefix with 'typename' to indicate a type
        d:\research\delegates\delegate_impl.h(44) : see reference to class template instantiation 'CStaticDelegate0<TRet>' being compiled
d:\research\delegates\delegate_impl.h(31) : error C2146: syntax error : missing ';' before identifier 'Invoke'
d:\research\delegates\delegate_impl.h(31) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
d:\research\delegates\delegate_impl.h(31) : warning C4183: 'Invoke': missing return type; assumed to be a member function returning 'int'
d:\research\delegates\delegate_impl.h(52) : warning C4346: 'DelegateRetVal<T>::Type' : dependent name is not a type
        prefix with 'typename' to indicate a type
        d:\research\delegates\delegate_impl.h(69) : see reference to class template instantiation 'CStaticDelegateVoid0<TRet>' being compiled
Re[2]: Делегаты на C++
От: Аноним  
Дата: 19.12.06 11:12
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Александр Шаргин, Вы писали:


А>Версия делегатов для VC 6.0 не компилится под VC 8.0 Хотелось бы иметь общую рабочую для обоих студий версию


Вообщем под VC 8.0 надо заменить в обьявлениях функций

DelegateRetVal<TRet>::Type

на
typename DelegateRetVal<TRet>::Type


Re[2]: Велосипед
От: dad  
Дата: 19.12.06 14:21
Оценка:
AS>Но.
AS>а) Статья писалась в учебных целях, чтобы показать на не очень навороченном примере как делаются такие вещи.
AS>б) Код писался с прицелом на VC (в т. ч. 6.0), который с boost'ом не дружит.
AS>в) Мне просто было интересно дойти до этого самому и получить удовольствие от процесса.

не очень навороченный пример по ходу действия превратился в гору кода.
а то если вдруг понадобится делегант для константных методов, или методов, возвращающих значение?
так же есть проблемы с методами базовых классов, применительно к указателям на дочерние классы (не помню точно на что-то напарывался там)
(надо using Base::member; в объявлении писать)

Короче, как правило овинка не стоит выделки. Для самых общих случаев (0,1 параметр) можно
простейший bind организовать а для остальных — лучше под конкретные api сделать делегатов.
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[3]: Велосипед
От: dad  
Дата: 19.12.06 14:27
Оценка: 1 (1)
либо использовать готовое отполированное решение (boost)
вот тогда длействительно будет мало кода.
короче статья полезнее была бы если бы рассказывала как устроена и почему работает какая-нибудь готовая библиотека (boost) реализующая требуемый функционал
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[4]: Велосипед
От: Аноним  
Дата: 19.12.06 18:38
Оценка:
Здравствуйте, dad, Вы писали:


dad>либо использовать готовое отполированное решение (boost)

dad>вот тогда длействительно будет мало кода.
dad>короче статья полезнее была бы если бы рассказывала как устроена и почему работает какая-нибудь готовая библиотека (boost) реализующая требуемый функционал

Важна идея и подход, а реализовать одно и тоже можна по разному + не все используют boost к тому же за его лесом можна не увидеть сам принцип.

Автору
Re[5]: Велосипед
От: dad  
Дата: 19.12.06 20:19
Оценка:
А>Важна идея и подход, а реализовать одно и тоже можна по разному + не все используют boost к тому же за его лесом можна не увидеть сам принцип.

Именно об этом я и написал — разжевывать принцип на примере работающих бибилотек. вообще сорри — я дату не обратил внимания — для 2003 года статья очень ок
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[4]: Отчего boost такой вычурный?
От: johny5 Новая Зеландия
Дата: 20.12.06 00:05
Оценка:
G>boost::function штука несомнено мощная. Проникся. Но вот из-за этой мощности использовать ее мне как-то не хочется. Ну не нужна мне лямбда.

Я вот тоже долго пользовался своими велосипедами, которые принимают указатели на функции и мемберы в различных вариантах, но как только начал использовать boost::bind, был вынужден в свой велосипед встроить поддержку функторов..

Зато теперь я могу в Callback функции передавать свои параметры, игнорировать чужие, в общем как камень с души, щастлив

Вот, два хороших примера (верность синтаксиса — не главное):

№1:
bool SomeClass::on_button_click() { .. }

void SomeClass::func()
{
    boost::function< bool (const IButton* from_me) >  callback = boost::bind(on_button_click, this);
}



№2:
bool sort_func(const BigArray& a, int value1, int value2)
{
    return a[value1] < a[value2];
}

void some()
{
    BigArray arr;
    std::vector<int> indexes;

    std::sort(indexes.begin(), indexes.end(), boost::bind(sort_func, arr, _1, _2));
}


и т.д., в общем от bind-а меня теперь не отлучить
Re[5]: Отчего boost такой вычурный?
От: Sm0ke Россия ksi
Дата: 20.12.06 08:06
Оценка:
Здравствуйте, johny5, Вы писали:

<...skip...>

J>и т.д., в общем от bind-а меня теперь не отлучить


А можно ли с помощью boost 'а в качестве оконной процедуры в win api подсунуть нестатический метод с объектом?
Re[6]: Отчего boost такой вычурный?
От: johny5 Новая Зеландия
Дата: 21.12.06 00:19
Оценка:
S>А можно ли с помощью boost 'а в качестве оконной процедуры в win api подсунуть нестатический метод с объектом?

Я как понимаю, оконная процедура в win api принимает указатель на функцию?
Тогда ответ — нет, bind предоставляет функтор, функтор в общем случае не представим в виде указателя на функцию.

Простейший способ это сделать, это зарегистрировать все окна в глобальной переменной вот так:
(никогда не использовал лямбду до этого, если что, синтаксис знающие люди поправят )


#include "boost/lambda.hpp"
std::vector<WindowBase*>  windows;


template<typename WNDCLASS>
void callback_func(Event event)
{
    WindowBase* wnd = *std::find_if(windows.begin(), windows.end(), typeid(*_1) == typeid(WNDCLASS));
    wnd->on_event(event)
}


//где то ещё..

WindowBase::WindowBase()
{
    windows.push_back(this);
}
WindowBase::~WindowBase()
{
    windows.erase(std::find(windows.begin(), windows.end(), this));
}


&callback_func<HelloWindow> можно передавать в WINAPI.
Re[3]: Велосипед
От: Celestial Россия http://video.google.com/googleplayer.swf?docId=1055185227485133586
Дата: 21.12.06 10:41
Оценка:
Мне бы тоже очень пригодился бы ваш вариант
если можно на infernal-demon[собака]mail.ru
Спасибо !
Re: Делегаты на C++
От: Smooky Россия  
Дата: 22.12.06 09:18
Оценка:
Здравствуйте, Александр Шаргин, Вы писали:

АШ>Статья :

АШ>Делегаты на C++
Автор(ы): Александр Шаргин
Дата: 19.03.2003
Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках "чистого" C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.


АШ>Авторы :

АШ>Александр Шаргин

АШ>Аннотация :

АШ>Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках "чистого" C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.

Было бы неплохо всё-таки разжевать еще, как на своих аллокаторах это сделать, всё таки предоставлять читателю, скажем так, не совсем тривиальную задачу, как-то незакончено... Статья понравилась! Просто чес слова, извините за грубость, ну задолбали с этим БУСТОМ...! Да ОЧЕНЬ много, очень много кто НЕ пользует его по многим объективным причинам. Да и собсна из тех кто пользует, толком никто и незнает, как там всё устроено...
Только Путин, и никого кроме Путина! О Великий и Могучий Путин — царь на веки веков, навсегда!
Смотрю только Соловьева и Михеева, для меня это самые авторитетные эксперты.
КРЫМ НАШ! СКОРО И ВСЯ УКРАИНА БУДЕТ НАШЕЙ!
Re: Делегаты на C++
От: mikhail.reload Россия  
Дата: 25.01.08 19:19
Оценка:
Здравствуйте, Александр Шаргин, Вы писали:

АШ>Статья :

АШ>Делегаты на C++
Автор(ы): Александр Шаргин
Дата: 19.03.2003
Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках "чистого" C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.


АШ>Авторы :

АШ>Александр Шаргин

АШ>Аннотация :

АШ>Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках "чистого" C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.




Я немного "обжегся", не посомтрев на реализацию. Используется dynamic_cast

C_METHOD_DELEGATE<TObj, TRet TEMPLATE_ARGS>* pMethodDel =
dynamic_cast<C_METHOD_DELEGATE<TObj, TRet TEMPLATE_ARGS>* >(pDelegate);

так чтo,народ, проверьте ключ компиляции /GR. Если он не стоит — будет генериться исключение. В моем случае оно лихо ловилось, а объект из списка не удалялся.

А вообще — спасибо автору.
Re: Делегаты на C++
От: my_soul  
Дата: 04.08.08 08:34
Оценка:
Добрый день!
Подскажите, как это работает

Вот у вас есть определение:

template <class TObj, class TRet TEMPLATE_PARAMS>
I_DELEGATE<TRet TEMPLATE_ARGS>* NewDelegate(TObj* pObj, TRet (TObj::*pMethod)(PARAMS))
{
  return new C_METHOD_DELEGATE<TObj, TRet TEMPLATE_ARGS> (pObj, pMethod);
}


По моей логике, чтобы это хотябы скомпилировалось, надо передать в шаблон тип класса, метод которого
передается в делеат.
NewDelegate<CMyClass, и т.д.>(pMyClass, &CMyClass::Method);

Однако, этого не требуется. Как такого вы достигли?
Re[2]: Делегаты на C++
От: Юрий Жмеренецкий ICQ 380412032
Дата: 04.08.08 11:40
Оценка:
Здравствуйте, my_soul, Вы писали:

_>Добрый день!

_>Подскажите, как это работает

_>Вот у вас есть определение:


_>
_>template <class TObj, class TRet TEMPLATE_PARAMS>
_>I_DELEGATE<TRet TEMPLATE_ARGS>* NewDelegate(TObj* pObj, TRet (TObj::*pMethod)(PARAMS))
_>{
_>  return new C_METHOD_DELEGATE<TObj, TRet TEMPLATE_ARGS>(pObj, pMethod);
_>}
_>


_>По моей логике, чтобы это хотябы скомпилировалось, надо передать в шаблон тип класса, метод которого

_>передается в делеат.
_>NewDelegate<CMyClass, и т.д.>(pMyClass, &CMyClass::Method);

_>Однако, этого не требуется. Как такого вы достигли?

В случае шаблона функции(NewDelegate) это не обязательно, в отличии от шаблонного класса(C_METHOD_DELEGATE). Типы будут выведены исходя из фактических типов переданных аргументов. Собственно эта функция и нужна для того, чтобы при создании объекта класса C_METHOD_DELEGATE не приходилось указывать явно его параметры.
Re[3]: Делегаты на C++
От: my_soul  
Дата: 04.08.08 12:33
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>В случае шаблона функции(NewDelegate) это не обязательно, в отличии от шаблонного класса(C_METHOD_DELEGATE). Типы будут выведены исходя из фактических типов переданных аргументов. Собственно эта функция и нужна для того, чтобы при создании объекта класса C_METHOD_DELEGATE не приходилось указывать явно его параметры.



Я тогда не понимаю:

NewDelegate(&obj, &CMyClass::func);



CMethodDelegate0 del(&obj, &CMyClass::func);


Почему для функции компилятор догадывается какой тип надо подставить в шаблон, а для класса нет?..
Re[4]: Делегаты на C++
От: Юрий Жмеренецкий ICQ 380412032
Дата: 04.08.08 13:20
Оценка: 2 (1)
Здравствуйте, my_soul, Вы писали:

_>Я тогда не понимаю:


_>
_>NewDelegate(&obj, &CMyClass::func);
_>



_>
_>CMethodDelegate0 del(&obj, &CMyClass::func);
_>


_>Почему для функции компилятор догадывается какой тип надо подставить в шаблон, а для класса нет?..


Первая конструкция — это выражение(expression), а второй — определение объекта типа CMethodDelegate0. Как мы можем определить объект неизвестного типа ?

Кроме того, возможны ситуации с шаблонным конструктором:

template<class>
struct A
{
  template<class t>
  A(t){}
};
//...
A a(1); // Какой здесь тип у a ?
Re[5]: Делегаты на C++
От: my_soul  
Дата: 04.08.08 13:29
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>Первая конструкция — это выражение(expression), а второй — определение объекта типа CMethodDelegate0. Как мы можем определить объект неизвестного типа ?


ЮЖ>Кроме того, возможны ситуации с шаблонным конструктором:


ЮЖ>
ЮЖ>template<class>
ЮЖ>struct A
ЮЖ>{
ЮЖ>  template<class t>
ЮЖ>  A(t){}
ЮЖ>};
ЮЖ>//...
ЮЖ>A a(1); // Какой здесь тип у a ?
ЮЖ>




Ясно! Спасибо!
Re: Делегаты на C++
От: Anton_86 Украина  
Дата: 25.11.08 15:41
Оценка:
Здравствуйте, Александр Шаргин, Вы писали:

К сожалению данный код не работает корректно в VS2008:

Ваш код:

for(it = m_DelegateList.begin(); it != --m_DelegateList.end(); ++it)
       static_cast<IDelegate*> (*it)->Invoke(ARGS);


Мне пришлось поменять на


if ( !m_DelegateList.empty() )
{
    for(it = m_DelegateList.begin(); it != --m_DelegateList.end(); ++it)
       static_cast<IDelegate*> (*it)->Invoke(ARGS);
}


так как рантайм VS2008 выбрасывает исключение нарушения границ доступа при попытке декрементировать итератор который возвращен методом end().
Best Regards. Anton.
Re: "в языке C++ операторы не наследуются (?)"
От: Аноним  
Дата: 25.11.08 18:29
Оценка:
Раз уж подняли эту тему, такой вопрос:

Насторожила фраза в статье: "Дело в том, что в языке C++ операторы не наследуются."
Попробовал на VC++2005 — наследуются. И в Стандарте не нашёл подтверждения обратному.
Буду благодарен за пояснения особенностей наследования операторов в С++.

Заранее спасибо.

PS
По ходу чтения возникла мысль: не проще ли генерировать классы на каком-либо скрипте?
Re[2]: "в языке C++ операторы не наследуются (?)"
От: johny5 Новая Зеландия
Дата: 26.11.08 00:24
Оценка:
А>PS
А> По ходу чтения возникла мысль: не проще ли генерировать классы на каком-либо скрипте?

Кстати, не знает ли кто простой и проверенный способ в студии по описанию класса генерить операторы ==, !=, =; конструктор по умолчанию, копирования, макросы сериализации (тут ессно нуно ручками будет что то в чём то прописать), и прочий мегатонный мусор. Плюс стандартные #ifndef BLABLABLA_H_INCL__ мусор ___ #define BLABLABLA_H_INCL__ мусор ___ и #include в .cpp файле.

Чтоб вот нажал кнопку, бах и всё на месте..
Желательно было б конечно в идеале уметь обновлять все эти структуры при обновлении полей.

Или хотя бы макрос, который оформлял бы дефиницию функции в cpp по её декларации в классе в h, т.е.

.h файл
class A
{
  virtual int method(const Type& .. ) const;
  ..
};


в

.cpp файл
int A::method(const Type& .. ) const
{
}
Re[3]: "в языке C++ операторы не наследуются (?)"
От: eHomo  
Дата: 26.11.08 09:51
Оценка: +1
Здравствуйте, johny5, Вы писали:

А>>PS

А>> По ходу чтения возникла мысль: не проще ли генерировать классы на каком-либо скрипте?

J>Кстати, не знает ли кто простой и проверенный способ в студии по описанию класса генерить операторы ==, !=, =; конструктор по умолчанию, копирования, макросы сериализации (тут ессно нуно ручками будет что то в чём то прописать), и прочий мегатонный мусор. Плюс стандартные #ifndef BLABLABLA_H_INCL__ мусор ___ #define BLABLABLA_H_INCL__ мусор ___ и #include в .cpp файле.


J>Чтоб вот нажал кнопку, бах и всё на месте..

J>Желательно было б конечно в идеале уметь обновлять все эти структуры при обновлении полей.

J>Или хотя бы макрос, который оформлял бы дефиницию функции в cpp по её декларации в классе в h, т.е.


J>.h файл

J>
J>class A
J>{
J>  virtual int method(const Type& .. ) const;
J>  ..
J>};
J>


J>в


J>.cpp файл

J>
J>int A::method(const Type& .. ) const
J>{
J>}
J>


Visual Assist
Re[2]: Делегаты на C++
От: Кодт Россия  
Дата: 26.11.08 10:56
Оценка:
Здравствуйте, Anton_86, Вы писали:

<>
Вообще-то, если коллекция пуста, то непонятно, что возвращать.
Т.е.
TRet Invoke(PARAMS)
{
  if(!m_DelegateList.empty())
  {
      for(......) (*it)->Invoke(ARGS);
      return m_DelegateList.back()->Invoke(ARGS);
  }
  else
  {
    // на выбор
    assert(! "нечего вызывать, нечего возвращать, щас вылечу нафиг");
    throw SomeDelegateException();
    return TRet();
  }
}


А ещё остаётся за кадром такой момент, как изменение списка во время его обхода.
Тут нужна или двойная буферизация,
vector<IDelegate*> snapshot; // вектор дешевле списка, поэтому копировать удобнее в него
snapshot.reserve(m_DelegateList.size());
snapshot.insert(m_DelegateList.begin(), m_DelegateList.end());
// далее - как с гусём :)

... или внимательность к свежедобавленным и свежеудаляемым элементам.
Свежедобавленные в конец — будут учитываться, поскольку мы проверяем фактический конец на каждой итерации цикла. (А вот если бы использовали for_each, то там запомнили бы итератор на предпоследний элемент на момент начала работы).
Свежеудалённые — болезненнее, так как может быть удалён текущий элемент, а итератор на него станет невалидным.
Не реентерабельная версия Invoke — в паре с Remove и RemoveAll может выглядеть так
DelegateList::iterator m_next;
.....
void Remove(IComparableDelegate* pDelegate)
{
  .....
  if(it == m_next)
    ++m_next;
  m_DelegateList.erase(it);
  .....
}
void RemoveAll()
{
  .....
  m_next = m_DelegateList.end();
}
TRet Invoke(PARAMS)
{
  DelegateList::iterator it = m_DelegateList.begin();
  while(true)
  {
    if(it == m_DelegateList.end()) { assert(!"всё-таки вылетели!!!"); return TRet(); }
    m_next = it; ++m_next;
    if(m_next == m_DelegateList.end()) { return (*it)->Invoke(ARGS); }
    (*it)->Invoke(ARGS);
    it = m_next;
  }
}

Реентерабельная... у, это сложно.
Перекуём баги на фичи!
Re[3]: "в языке C++ операторы не наследуются (?)"
От: jazzer Россия Skype: enerjazzer
Дата: 27.11.08 00:28
Оценка: +1
Здравствуйте, johny5, Вы писали:

А>>PS

А>> По ходу чтения возникла мысль: не проще ли генерировать классы на каком-либо скрипте?

J>Кстати, не знает ли кто простой и проверенный способ в студии по описанию класса генерить операторы ==, !=, =; конструктор по умолчанию, копирования, макросы сериализации (тут ессно нуно ручками будет что то в чём то прописать), и прочий мегатонный мусор. Плюс стандартные #ifndef BLABLABLA_H_INCL__ мусор ___ #define BLABLABLA_H_INCL__ мусор ___ и #include в .cpp файле.


J>Чтоб вот нажал кнопку, бах и всё на месте..

J>Желательно было б конечно в идеале уметь обновлять все эти структуры при обновлении полей.

Кстати, даже если ты будешь пользоваться своим макросом, все равно операторы лучше добавлять через Boost.Operators — там тебе придется добавить всего по одной функции на оператор, остальные она сгенерит сама, пользуясь этой функцией.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Проблема с копированием делегатов?
От: Аноним  
Дата: 31.01.09 18:16
Оценка:
Здравствуйте, Александр Шаргин, Вы писали:

АШ>Статья :

АШ>Делегаты на C++
Автор(ы): Александр Шаргин
Дата: 19.03.2003
Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках "чистого" C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.


АШ>Авторы :

АШ>Александр Шаргин

АШ>Аннотация :

АШ>Делегаты в CLR удобны, типобезопасны и эффективны. Последнее время на форумах RSDN часто поднимается вопрос о том, можно ли реализовать делегаты с аналогичными свойствами, оставаясь в рамках "чистого" C++. Оказывается, это вполне возможно. В этой статье я покажу, как это сделать.

Возникла проблема с копированием делегатов от одного обьекта к другому:


    C_DELEGATE(const C_DELEGATE<TRet TEMPLATE_ARGS>& x_right)
    {
        this.RemoveAll();
        gslIDelegate* delegate_ptr=x_right.GetDelegates(true);
        while(delegate_ptr!=0)
        {
            this.operator+=(delegate_ptr); //Здесь копируются указатели
            delegate_ptr=x_right.GetDelegates();
        };
    };

    C_DELEGATE<TRet TEMPLATE_ARGS>& operator=(C_DELEGATE<TRet TEMPLATE_ARGS>& x_right)
    {
        RemoveAll();
        gslIDelegate* delegate_ptr=x_right.GetDelegates(true);
        while(delegate_ptr!=0)
        {
            operator+=(delegate_ptr); //Здесь копируются указатели
            delegate_ptr=x_right.GetDelegates();
        };

        return *this;
    };

        void RemoveAll()
        {
                DelegateList::iterator it;
                for(it = m_DelegateList.begin(); it != m_DelegateList.end(); ++it)
                   delete (*it); //Здесь указатели прибиваются

                m_DelegateList.clear();
        InitIteratorDelegates();
       }

       ~C_DELEGATE() { RemoveAll(); }


То есть такой псевдокод не работает:

   class Object
   {
      C_DELEGATE* object_delegate;

      Object()
      {
         object_delegate=new C_DELEGATE();
      };

      Object(const Object& x_right)
      {
         object_delegate=new C_DELEGATE();
         *object_delegate=*(x_right.object_delegate); //Здесь скопируются указатели
      };

      Object& operator=(const Object& x_right)
      {
          *object_delegate=*(x_right.object_delegate); //Здесь скопируются указатели
          return *this;
      };

      C_DELEGATE* get_delegate() const
      {
         return object_delegate;
      };

      ~Object()
      {
         delete object_delegate;
      };
   };

   class Events
   {
       void Test();
   };

   //Тогда код:

   Events events;

   void main()
   {
      Object object2;

      {
         Object object1;
         object1.get_delegate()->operator +=(NewDelegate(events, &Events::Test));

         Object object2=object1; //Хочу скопировать объект вместе с его делегатами;
      }; //Здесь object1 рушится вместе с указателями в ~C_DELEGATE, а указатели делегатов в object2 становятся не валидными 
      
      object2.get_delegate()->operator ()(); //CRASH! потому как object1 забрал в небытие указатели на делегаты с собой.
   };


Понятно что в C_DELEGATE(const C_DELEGATE<TRet TEMPLATE_ARGS>& x_right) и operator== нужно копировать не указатели а делать их реальные копии, но что то не могу понять как это сделать?

Спасибо!
Re[2]: Проблема с копированием делегатов?
От: Аноним  
Дата: 31.01.09 18:23
Оценка:
Поправка в коде:

  //Тогда код:

   Events events;

   void main()
   {
      Object object2;

      {
         Object object1;
         object1.get_delegate()->operator +=(NewDelegate(events, &Events::Test));

         object2=object1; //Хочу скопировать объект вместе с его делегатами;
      }; //Здесь object1 рушится вместе с указателями в ~C_DELEGATE, а указатели делегатов в object2 становятся не валидными 
      
      object2.get_delegate()->operator ()(); //CRASH! потому как object1 забрал в небытие указатели на делегаты с собой.
   };
Re[3]: Up...
От: Аноним  
Дата: 01.02.09 22:34
Оценка:
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.