Делегаты на C++ | страница 8




> // Добавляем ссылку на OutputToFile.

> // Вызываем её через делегата.

> callback += NewDelegate(App::OutputToFile);

> if (!callback.IsNull()) callback("2");


> // Добавляем ссылку на OutputToConsole.

> // Вызывается вся цепочка:

> // сначала OutputToFile, потом OutputToConsole.

> callback += NewDelegate(&app, &App::OutputToConsole);

> if (!callback.IsNull()) callback("3");


> // Убираем ссылку на OutputToFile.

> // Вызывается только OutputToConsole.

> callback -= NewDelegate(App::OutputToFile);

> if (!callback.IsNull()) callback("4");


> // Убираем оставшуюся ссылку на OutputToConsole.

> callback -= NewDelegate(&app, &App::OutputToConsole);

> if (!callback.IsNull()) callback("5");

>}


Законченный проект Visual Studio 7.0, содержащий этот пример, можно найти на сопровождающем компакт-диске.

Те же и Visual C++ 6.0

На этом можно было бы поставить точку, но остаётся ещё одна нерешённая проблема. Если вы попытаетесь скомпилировать приведённый пример в Visual C++ 6.0, у этого компилятора возникнут проблемы при задании параметра шаблона делегата TRet=void. Дело в том, что в этом случае VC6 не может корректно обработать конструкцию вида:

>virtual TRet Invoke(TP1 p1) {

> // VC6 полагает, что нельзя возвращать выражение типа void.

> return (m_pObj-›*m_pMethod)(p1);

>}


Данная конструкция совершенно законна в соответствии с пунктом 6.6.3/3 Стандарта языка C++. Но VC6 об этом не знает. Поэтому нам придётся искать обходные пути. Чтобы обойти эту недоработку компилятора, необходимо отдельно реализовать все классы CDelegateX для случая TRet=void. Идеальным инструментом для этой цели служит частичная специализация шаблонов, но VC6 не поддерживает и эту возможность языка C++. В результате решение задачи на VC6 превращается в занимательную головоломку.

Первой моей мыслью было воспользоваться техникой, описанной Павлом Кузнецовым в этом же номере журнала в статье "Симуляция частичной специализации". К сожалению, выяснилось, что эта методика неприменима для реализации делегатов на VC6 сразу по двум причинам. Первая причина состоит в том, что использование полиморфизма совместно с навороченными шаблонными конструкциями оказывается "не по зубам" VC6, и он отказывается компилировать классы CStaticDelegateX и CMethodDelegateX, переписанные с использованием частичной специализации. На самом деле, это ещё полбеды, так как эти классы являются внутренней деталью реализации, и применять к ним частичную специализацию не обязательно. Вторая причина носит более фундаментальный характер. Дело в том, что симуляция частичной специализации для класса