2

好奇心から、C#の複数のデリゲートパターンを模倣する基本的なC++クラスを作成してみようと思いました。以下のコードはほとんどすべてのタイプセーフティを失うという厄介な犠牲を払って仕事をしますが、va_listを設定するために初期ダミーパラメータを使用する必要があるのは実際には少し外れているようです。これなしでva_listを使用する方法はありますか?(たとえば)ブーストを使用してこれを行う方法があることは確かですが、標準ライブラリだけを使用する非常に単純なものを目指していました。

#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;
}
4

2 に答える 2

4

C ++で省略記号を使用する関数は、Cとの互換性のためだけです。C++を使用すると、関数で一時ヘルパーオブジェクトを返し、可変数の引数を渡すためのCallテンプレートを追加します。operator%次のように使用するには:

cDelegateCaller.Call() % 2 % "Hello" % sString; // dummy argument isn't required

あなたの質問に関しては、Standardはva_start名前のない引数にアクセスする前に呼び出す必要があります。またva_start、関数定義の変数パラメーターリストの右端のパラメーターの識別子である2番目の引数が必要です。

于 2009-09-17T06:52:20.007 に答える
0

Kirillの回答から、テンプレートの引数結合関数を使用して、タイプセーフなデリゲートを作成することが可能であると結論付けることができます。この関数にもダミーの開始点が必要ですが、型安全性の利点があります。

FastFormatライブラリはこれを使用し、boostはこれを使用します。私はかつて、別の質問への回答で別の例を提供しました。

于 2009-09-17T07:25:35.963 に答える