Из любопытства я подумал, что попробую написать базовый класс C++, который имитирует множественный шаблон делегата C#. Кодекс ниже в основном выполняет эту работу, при этом неприятная жертва потеряет почти все виды безопасности, но при использовании исходного параметра фиктивной настройки для настройки va_list действительно кажется немного выключенным. Есть ли способ использовать va_list без этого? Я действительно понимаю, что есть способы сделать это с помощью (например) повышения, но я стремился к чему-то мертвому простому, который использовал только стандартную библиотеку.Функция Variadic без указанного первого параметра?
#include <vector>
#include <iostream>
#include <string>
#include <stdarg.h>
#include <algorithm>
using namespace std;
class CDelegate
{
public:
virtual bool operator()(va_list params) = 0;
};
class CMultipleDelegateCaller
{
public:
typedef vector<CDelegate*> CDelegateVector;
CMultipleDelegateCaller& operator+=(CDelegate &rDelegate)
{
m_apDelegates.push_back(&rDelegate);
return (*this);
}
CMultipleDelegateCaller& operator-=(CDelegate &rDelegate)
{
CDelegateVector::iterator iter =
find(m_apDelegates.begin(), m_apDelegates.end(), &rDelegate);
if (m_apDelegates.end() != iter) m_apDelegates.erase(iter);
return (*this);
}
bool Call(int iDummy, ...)
{
va_list params;
CDelegate* pDelegate;
CDelegateVector::iterator iter;
for (iter = m_apDelegates.begin(); iter != m_apDelegates.end(); ++iter)
{
pDelegate = *iter;
va_start(params, iDummy);
if (!(*pDelegate)(params)) return false;
va_end(params);
}
return true;
}
private:
CDelegateVector m_apDelegates;
};
class CTestDelegate:
public CDelegate
{
public:
CTestDelegate():m_iId(++s_iCount) {}
virtual bool operator()(va_list params)
{
int iIntParam = va_arg(params, int);
char* szCharPtrParam = va_arg(params, char*);
string* psStringParam = va_arg(params, string*);
cout<<m_iId<<"{"
<<iIntParam<<", "
<<szCharPtrParam<<", "
<<*psStringParam<<"}"<<endl;
return true;
}
int m_iId;
static int s_iCount;
};
int CTestDelegate::s_iCount = 0;
int main(int argc, char* argv[])
{
CMultipleDelegateCaller cDelegateCaller;
CTestDelegate cTestDelegate1;
CTestDelegate cTestDelegate2;
cout<<"--------------------"<<endl;
cDelegateCaller += cTestDelegate1;
cDelegateCaller += cTestDelegate2;
string sString("World");
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cDelegateCaller -= cTestDelegate1;
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cDelegateCaller -= cTestDelegate2;
cDelegateCaller.Call(1, 2, "Hello", &sString);
cout<<"--------------------"<<endl;
cin>>sString;
return 0;
}
Как это можно было бы использовать для вызова функции? Вызов будет выполняться перед каждым из операторов модуля, поэтому параметры еще не были переданы. – FlintZA
Фактическое действие будет выполняться в деструкторе временного объекта, возвращаемого функцией 'Call'. Вы можете найти здесь образец - http://stackoverflow.com/questions/1394053/how-to-write-a-generic-alert-message-using-win32/1394069#1394069 –
Итак, ссылаясь на вышеуказанный вопрос, и один предоставлен xtofl, у меня есть внутренний помощник, который будет возвращен вызовом, и имеет оператор%, который добавляет аргументы во внутренний список arglist (как определено xtofl (http://stackoverflow.com/questions/1350657/variable-parameter -function-how-to-make-it-type-safe-and-more-importantful/1361620 # 1361620). В своем деструкторе он выполняет итерацию по списку делегатов CDelegateCaller, но как эти аргументы передаются делегатскому оператору() в таким образом, что пользователю не нужно реализовывать несколько рекурсивных функций? – FlintZA