参考水平第2部分

时间:2011-06-04 18:16:57

标签: c++ templates function-pointers

Expanding on this question,看起来我没有提供足够的细节。

我有一个名为CallbackObject的对象,它被设计为包含一个对象实例,以及要调用的函数的信息,以及在调用时传递的参数。

template <typename objectType,
          typename memberFunctionPtrType,
          typename memberFcnArg1Type>
struct CallbackObject1
{
  objectType obj ;
  memberFunctionPtrType fcnPtr ;
  memberFcnArg1Type arg1 ;

  CallbackObject1(objectType iObj,
                  memberFunctionPtrType iFcnPtr,
                  memberFcnArg1Type iArg1 )
  {
    obj = iObj ;
    fcnPtr = iFcnPtr ;
    arg1 = iArg1 ;
  }

  void exec()
  {
    (obj.*fcnPtr)( arg1 ) ;
  }
} ;

使用示例:

struct Point
{
  float x,y ;
  void print( int numTimes )
  {
    for( int i = 0 ; i < numTimes ; i++ )
      printf( "%f %f\n", x, y ) ;
  }
} ;

typedef void (Point::* PointPrintFcnType)( int ) ;

int main()
{
  Point p ;
  p.x=p.y=1;

  CallbackObject1<Point, PointPrintFcnType, int> ocall( p, &Point::print, 5 );
  ocall.exec() ;
}

我遇到的唯一问题是如果objectType是指针类型,那么(obj.*fcnPtr)会失败,因为如果obj是a,它应该真正读取( (*obj).*fcnPtr)(obj->*fcnPtr)指针。

现在我有一个解决方案,我在其中定义另一个 CallbackObject类,如下所示:

template <typename pObjectType,
          typename memberFunctionPtrType,
          typename memberFcnArg1Type>
struct CallbackPObject1
{
  pObjectType obj ;
  memberFunctionPtrType fcnPtr ;
  memberFcnArg1Type arg1 ;

  CallbackPObject1(pObjectType iObj,
                  memberFunctionPtrType iFcnPtr,
                  memberFcnArg1Type iArg1 )
  {
    obj = iObj ;
    fcnPtr = iFcnPtr ;
    arg1 = iArg1 ;
  }

  void exec()
  {
    (obj->*fcnPtr)( arg1 ) ;
  }
} ;

但这充其量是苛刻的,并且在最坏的情况下难以使用,如果其他人正在使用此代码,如果使用的对象类型实际上是指针,则必须创建不同类型的Callback对象。

有什么方法吗?

3 个答案:

答案 0 :(得分:1)

这是一个示例辅助函数,假设返回void,一个参数,并且不需要处理多个间接级别:

template <typename T, typename F, typename A>
inline void invoke(T& obj, F func, const A& arg)
{
    (obj.*func)(arg);
}

template <typename T, typename F, typename A>
inline void invoke(T* obj, F func, const A& arg)
{
    (obj->*func)(arg);
}

如果您需要处理多个间接级别,可以用以下代码替换第二个函数:

template <typename T, typename F, typename A>
inline void invoke(T* obj, F func, const A& arg)
{
    invoke(*obj, func, arg);
}

这将以递归方式剥离间接级别,直到您最终得到可以调用成员函数的内容。

然后您可以像这样编写exec()函数:

void exec()
{
    invoke(obj, fcnPtr, arg1);
}

答案 1 :(得分:0)

将多态函数对象(如boost::function)与函数生成函数(如boost::bind)结合使用。这是一个非常优越的解决方案 - 天赋在生成仿函数时发生,而不是在调用时发生,并且可以调用任何可以使用正确签名调用的函数对象。

答案 2 :(得分:0)

好的,在我previous question

上应用“重载”方法
template <typename objectType,
          typename memberFunctionPtrType,
          typename memberFcnArg1Type>
struct CallbackObject1 : public Callback
{
  objectType obj ;
  objectType *pObj ;
  memberFunctionPtrType fcnPtr ;
  memberFcnArg1Type arg1 ;

  CallbackObject1(objectType iObj,
                  memberFunctionPtrType iFcnPtr,
                  memberFcnArg1Type iArg1 )
  {
    obj = iObj ;
    pObj = 0 ;
    fcnPtr = iFcnPtr ;
    arg1 = iArg1 ;
  }

  CallbackObject1(objectType *iObj,
                  memberFunctionPtrType iFcnPtr,
                  memberFcnArg1Type iArg1 )
  {
    pObj = iObj ;
    fcnPtr = iFcnPtr ;
    arg1 = iArg1 ;
  }

  void exec()
  {
    if( pObj )
      (pObj->*fcnPtr)( arg1 ) ;
    else
      (obj.*fcnPtr)( arg1 ) ;
  }
} ;

使用

  typedef void (Point::* PointPrintFcnType)( int ) ;

  Point p ;
  p.x=p.y=1;

  CallbackObject1<Point, PointPrintFcnType, int> ocall( p, &Point::print, 5 );
  ocall.exec() ;

  CallbackPObject1<Point*, PointPrintFcnType, int> ocallP( &p, &Point::print, 2 );
  ocallP.exec() ;

它的工作原理相当不错,但它并不像我想的那样干净。