Делегаты на 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 можно найти на сопровождающем компакт-диске.