C++11 C++;11及其后:如何存储在模板化方法中接收的对象指针和方法指针,以供以后使用?

C++11 C++;11及其后:如何存储在模板化方法中接收的对象指针和方法指针,以供以后使用?,c++11,callback,function-templates,pointer-to-member-functions,C++11,Callback,Function Templates,Pointer To Member Functions,问题:我有一个模板函数,它接受模板param类的对象指针和指向该类方法的方法指针。然后我可以立即对该对象调用该方法。但我不想马上打电话。相反,我希望保存这两个指针以备将来使用,并在以后的代码中调用它们,而这些代码在上下文中不知道该类型是什么。 在旧式C/C++99代码中,我们传入一个函数指针和一个void*用户数据指针,指向将执行回调的代码(例如,在计时器结束时,用户事件等),我们几乎总是传入一个对象指针作为用户数据,并编写一行C函数,将用户数据指针强制转换为该类型,并调用对象上的方法: voi

问题:我有一个模板函数,它接受模板param类的对象指针和指向该类方法的方法指针。然后我可以立即对该对象调用该方法。但我不想马上打电话。相反,我希望保存这两个指针以备将来使用,并在以后的代码中调用它们,而这些代码在上下文中不知道该类型是什么。

在旧式C/C++99代码中,我们传入一个函数指针和一个
void*
用户数据指针,指向将执行回调的代码(例如,在计时器结束时,用户事件等),我们几乎总是传入一个对象指针作为用户数据,并编写一行C函数,将用户数据指针强制转换为该类型,并调用对象上的方法:

void TimerCB( void* pvUserData, void* pvCallerData ) {
    ( (Foo*) pvUserData )->TimerDone( pvCallerData );
}
在C++11中,
std::function
允许我们传入lambdas和
std::bind
,或者一个没有用户数据的C函数

然而,在实践中,几乎每次我都只想对当前对象调用一个方法。我可以用lambda或bind来实现,但它很冗长:

  class Timer {

      :

      virtual void SubscribeTimer( const char* pszTime,
                                   std::function<void(Data*)> pfn );
  };

  void Timer::SubscribeTimer( const char* pszTime,
                             std::function<void(Data*)> pfn ) {
      cout << "  calling std::function\n";
      Data d;
      pfn( &d );
  }

  // Inside methods of class Foo:

  SubscribeTimer( "14:59:50", std::bind( &Foo::TimerDone, this, std::placeholders::_1 ) );

  SubscribeTimer( "14:59:50", [this](Data* pdata){this->TimerDone( pdata );} );
类计时器{
:
虚拟空订阅计时器(常量字符*pszTime,
std::函数pfn);
};
无效计时器::SubscribeTimer(常量字符*pszTime,
标准::功能(pfn){
cout TimerDone(pdata);};
如果我在编译时知道它们的对象的类,我可以传入方法指针,如下所示:

  class Timer {

      :

      virtual void SubscribeTimer( const char* pszTime,
                                   void (Foo::*pfn)( Data* pd ), Foo* pfoo );
  };

  void Timer::SubscribeTimer( const char* pszTime, void (Foo::*pfn)( Data* pd ), Foo* pfoo ) {
      cout << "  calling method\n";
      Data d;
      (pfoo->*pfn)( &d );
 }

  // Inside methods of class Foo:

  SubscribeTimer( "14:59:50", &Foo::TimerDone, this );
类计时器{
:
虚拟空订阅计时器(常量字符*pszTime,
无效(Foo::*pfn)(数据*pd),Foo*pfoo);
};
无效计时器::订阅计时器(const char*pszTime,void(Foo::*pfn)(数据*pd),Foo*pfoo){
法院*pfn)(&d);
}
//类Foo的内部方法:
SubscribeTimer(“14:59:50”,&Foo::TimerDone,this);
但是,这是不可接受的,因为我的Timer类属于项目的实用程序库级别,不需要知道像Foo这样的每个可能的用户类

好的,结果证明我可以模板化这个方法,这样我就不再需要知道Foo是什么类型的对象,或者这个方法是什么类型的方法。这样编译不会出错。(方法和类指针交换,因此可以清楚调用哪个重载函数。)

类计时器{
:
模板无效订阅计时器(常量字符*pszTime,T*p此,
无效(T::*pfn)(数据*pd));
};
模板void Foo::SubscribeTimer(const char*pszTime,T*pthis,
无效(T::*pmethod)(数据*pd)){

cout*pmethod)(&d);//您已经知道答案的所有部分(
std::function
,lambdas);您只需要将它们放在一起

std::function<void(Data*)> f = [=](Data* d) { (pthis->*pmethod)(d); }

好吧,与其说我的客户端软件自己编写挑剔的lambda,不如说他们只提供了对象和方法,我的模板将其转换为lambda,我将其处理为lambda,就像他们给了我一个lambda一样。很明显,现在你指出了这一点!我不知道为什么我没有弄明白。好吧,我想将t的类型限制为类型的对象Xyz或子类。我希望子类能够添加不在基类中的方法,并用这个函数注册它们,所以我想我需要T,我不能只写Xyz。但是什么是约束这些子类使用的最干净的方法呢?可能最简单的方法是
static_assert(std::is_base_of_v);
作为SubscribeTimer
中的第一行。尽管坦率地说我不明白这一点。如果你想能够调用任何方法,包括那些不是从
Xyz
继承的方法,为什么你还要关心这个类是从
Xyz
派生出来的?如果不是,它会停止工作吗?这是一个多线程应用程序。实际的callback可能是一个网络数据包,它与来自Xyz子类的数千个对象有关。它不是获取传入数据的线程直接顺序调用这些对象,而是在只有Xyz类对象具有的消息队列中对回调进行排队。然后,您可能还需要将
Xyz*
指针保存在某个位置调用回调(以便您可以从中获取消息队列)。一旦有了
Xyz*p=pthis;
或类似内容,这将有效地要求
T
Xyz
派生,否则此行将无法编译。
std::function<void(Data*)> f = [=](Data* d) { (pthis->*pmethod)(d); }
Data d;
f_member(&d);