没有指定第一个参数的变量函数?

时间:2009-09-17 06:08:30

标签: c++ variadic-functions

出于好奇,我想我会尝试编写一个基本的C ++类来模仿C#的多个委托模式。下面的代码主要完成了这项工作,几乎所有类型安全都遭受了令人讨厌的牺牲,但是必须使用初始的伪参数来设置va_list似乎确实有些偏差。有没有办法在没有这个的情况下使用va_list? 我确实知道有很多方法可以用(例如)boost来做到这一点,但我的目标是只使用标准库的简单方法。

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

2 个答案:

答案 0 :(得分:4)

在C ++中使用省略号的函数仅用于与C的兼容。使用C ++我将在Call函数中返回临时助手对象,并添加模板operator%以传递可变数量的参数。要按以下方式使用它:

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

关于您的问题,标准要求在访问未命名参数之前调用va_startva_start需要第二个参数,它是函数定义中变量参数列表中最右边参数的标识符。

答案 1 :(得分:0)

Kirill's answer之外,你可以得出结论,使用模板参数组合函数可以创建一个类型安全的委托。此函数需要一个虚拟起点,但具有类型安全的好处。

FastFormat库使用它,boost使用它,我曾在另一个问题的answer中提供了另一个例子。