Делегаты на C++ | страница 7
> }
> C_DELEGATE‹TRet TEMPLATE_ARGS›& operator-=(IDelegate* pDelegate) {
> Remove(pDelegate);
> return *this;
> }
> TRet operator()(PARAMS) {
> return Invoke(ARGS);
> }
>private:
> void Add(IDelegate* pDelegate) {
> if(pDelegate != NULL) m_DelegateList.push_back(pDelegate);
> }
> void Remove(IDelegate* pDelegate) {
> DelegateList::iterator it;
> for(it = m_DelegateList.begin(); it!= m_DelegateList.end(); ++it) {
> if((*it)-›Compare(pDelegate)) {
> delete (*it);
> m_DelegateList.erase(it);
> break;
> }
> }
> }
> void RemoveAll() {
> DelegateList::iterator it;
> for(it = m_DelegateList.begin(); it!= m_DelegateList.end(); ++it) delete (*it);
> m_DelegateList.clear();
> }
> TRet Invoke(PARAMS) {
> DelegateList::const_iterator it;
> for (it = m_DelegateList.begin(); it != --m_DelegateList.end(); ++it) (*it)-›Invoke(ARGS);
> return m_DelegateList.back()-›Invoke(ARGS);
> }
>private:
> DelegateList m_DelegateList;
>};
Вынеся обобщённый таким образом делегат в отдельный файл delegate_impl.h, мы можем сгенерировать его специализацию для любого количества параметров. Например, специализация делегата для пяти параметров получается так:
>// 5 parameters…
>#define SUFFIX 5
>#define TEMPLATE_PARAMS \
>, class TP1, class TP2, class TP3, class TP4, class TP5
>#define TEMPLATE_ARGS , TP1, TP2, TP3, TP4, TP5
>#define PARAMS TP1 p1, TP2 p2, TP3 p3, TP4 p4, TP5 p5
>#define ARGS p1, p2, p3, p4, p5
>#include "delegate_impl.h"
>#undef SUFFIX
>#undef TEMPLATE_PARAMS
>#undef TEMPLATE_ARGS
>#undef PARAMS
>#undef ARGS
Подобные фрагменты для наборов от 0 до 10 параметров можно включить в отдельный файл delegate.h, который и будут подключать пользователи делегатов.
Вот пример использования библиотеки делегатов, которую мы только что получили. Обратите внимание, что он практически полностью соответствует примеру на языке C#, с которого началась эта статья.
>#include ‹iostream›
>#include ‹fstream›
>#include ‹string›
>using namespace std;
>#include "delegate.h"
>class App {
>public:
> // Определяем делегат Callback,
> // который принимает 1 параметр и ничего не возвращает.
> typedef CDelegate1‹void, string› Callback;
> // Это метод класса App.
> void OutputToConsole(string str) { cout ‹‹ str ‹‹ endl; }
> // А это статический метод класса App.
> static void OutputToFile(string str) {
> ofstream fout("output.txt", ios::out | ios::app);
> fout ‹‹ str ‹‹ endl; fout.close();
> }
>};
>int main() {
> App app;
> // Создаём делегат.
> App::Callback callback = NULL;
> if (!callback.IsNull()) callback("1");