Делегаты на C++ | страница 11
> return new C_STATIC_DELEGATE‹TRet TEMPLATE_ARGS›(pFunc);
>}
>template‹class TRet TEMPLATE_PARAMS›
>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TRet (*pFunc)(PARAMS), UseVoid‹1›) {
> return new C_STATIC_DELEGATE_VOID‹TRet TEMPLATE_ARGS›(pFunc);
>}
Тем самым мы избавляемся от неоднозначности. Но возникает другая проблема. Теперь при вызове NewDelegate необходимо явно указывать, какая версия функции нам нужна:
>void f();
>int g();
>…
>NewDelegate(f, UseVoid‹1›());
>NewDelegate(g, UseVoid‹0›());
Чтобы избавиться от необходимости явно указывать параметр UseVoid, напишем третий вариант функции NewDelegate, который будет автоматически (причём на этапе компиляции) определять и вызывать нужную версию этой функции. Для реализации этой идеи нам потребуется механизм преобразования типа TRet в константу 1 (в случае TRet=void) или 0 (для всех остальных типов). Мы уже решали аналогичную задачу в классе DelegateRetVal, поэтому теперь решение записывается без труда:
>template‹class T›
>struct IsVoid {
> enum {
> Result = 0};
>};
>template‹› struct
>IsVoid‹void› {
> enum {Result = 1};
>};
Теперь воспользуемся классом IsVoid для выбора нужного варианта функции NewDelegate.
>template‹class TRet TEMPLATE_PARAMS›
>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TRet (*pFunc)(PARAMS)) {
> return NewDelegate(pFunc, UseVoid‹IsVoid‹TRet›::Result›());
>}
Аналогичным образом NewDelegate перегружается для случая создания объектов CMethodDelegate*:
>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TObj* pObj, TRet (TObj::*pMethod)(PARAMS), UseVoid‹0›) {
> return new C_METHOD_DELEGATE‹TObj, TRet TEMPLATE_ARGS› (pObj, pMethod);
>}
>template ‹class TObj, class TRet TEMPLATE_PARAMS›
>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TObj* pObj, TRet (TObj::*pMethod)(PARAMS), UseVoid‹1›) {
> return new C_METHOD_DELEGATE_VOID‹TObj, TRet TEMPLATE_ARGS› (pObj, pMethod);
>}
>template ‹class TObj, class TRet TEMPLATE_PARAMS›
>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TObj* pObj, TRet (TObj::*pMethod)(PARAMS)) {
> return NewDelegate(pObj, pMethod, UseVoid‹IsVoid‹TRet›::Result›());
>}
Если вас успели утомить эти "хождения по мукам", у меня есть для вас хорошая новость. Проблема, которую мы только что решили, была последней. Осталось заменить возвращаемые значения методов Invoke и operator() в классе CDelegate на DelegateRetVal‹TRet›::Type, чтобы получить законченную реализацию делегатов для Visual C++ 6.0.
Полную версию реализации делегатов для Visual C++ 6.0 можно найти на сопровождающем компакт-диске.