Читаем Делегаты на C++ полностью

ПРИМЕЧАНИЕ В этом месте может возникнуть соблазн избежать дублирования кода, породив класс CStaticDelegateVoidX от CStaticDelegateX и CMethodDelegateVoidX от CMethodDelegateX соответственно. К сожалению, это не будет работать. Хотя мы и переопределяем виртуальный метод Invoke в производных классах, теоретическая возможность обратиться к Invoke базовых классов сохраняется. Поэтому компилятор честно попытается сгенерировать их реализацию. А это в случае TRet=void в очередной раз приведёт к ошибке, которую мы пытаемся обойти. Поэтому дублирование кода в данном случае неизбежно.

Осталось сделать последний шаг - перегрузить функцию NewDelegate ещё двумя реализациями:

template‹class TRet TEMPLATE_PARAMS›

I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TRet (*pFunc)(PARAMS)) {

 return new C_STATIC_DELEGATE‹TRet TEMPLATE_ARGS›(pFunc);

}

template‹class TRet TEMPLATE_PARAMS›

I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(void (*pFunc)(PARAMS)) {

 return new C_STATIC_DELEGATE_VOID‹void TEMPLATE_ARGS›(pFunc);

}

 // Аналогично для CMethodDelegate*

В этом месте нас поджидает ещё один сюрприз. В большинстве случаев этот код будет работать, как по маслу. Но при задании TRet=void возникнет неоднозначность при обращении к функции NewDelegate. Правила разрешения перегрузки шаблонов функций описаны в разделе 14.5.5.2 Стандарта языка C++. В соответствии с этими правилами вторая версия NewDelegate не считается более специализированной, чем первая, так как для вызова обоих вариантов функции не требуется неявных преобразований типа.

Чтобы разрешить эту неоднозначность, придётся ввести дополнительный параметр функции NewDelegate, по которому и будет выбираться нужная версия функции:

// Параметр этого типа будет индикатором

template‹int use›

class UseVoid {};

template‹class TRet TEMPLATE_PARAMS›

I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TRet (*pFunc)(PARAMS), UseVoid‹0›) {

 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);

}

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных