C ++ 11及之后:如何存储在模板化方法中接收的对象指针和方法指针以供以后使用?
C++11 and after: How to store an object pointer and method pointer, received in a templatized method, for later use?
问题:我有一个模板函数,它接受模板参数 class 的对象指针和指向 class 的方法的方法指针。然后我可以立即对该对象调用该方法。但我不想立即调用它。相反,我想保存这两个指针以供将来使用,并在以后的代码中调用它们,而这些代码不会根据上下文知道该类型是什么。
在遗留 C/C++99 代码中,我们将一个函数指针和一个 void*
用户数据指针传递给将执行回调的代码(例如,在计时器完成时,用户事件等)我们几乎总是传入一个对象指针作为用户数据,并编写一个单行 C 函数,将用户数据指针转换为该类型并调用该对象的方法:
void TimerCB( void* pvUserData, void* pvCallerData ) {
( (Foo*) pvUserData )->TimerDone( pvCallerData );
}
在 C++11 中,std::function
让我们可以传入 lambda 和 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 );} );
我可以传入方法指针,如果我在编译时知道他们对象的class,就像这样:
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 );
但是,这是不可接受的,因为我的计时器 class 是项目的实用程序库级别,不需要像 Foo 这样的每个可能的用户 class 都知道.
好的,事实证明我可以将该方法模板化,因此我不再需要知道 Foo 是什么类型的对象或该方法是什么方法。这编译没有错误。 (方法和 class 指针交换,因此很清楚调用了哪个重载函数。)
class Timer {
:
template<typename T> void SubscribeTimer( const char* pszTime, T* pthis,
void (T::*pfn)( Data* pd ) );
};
template<typename T> void Foo::SubscribeTimer( const char* pszTime, T* pthis,
void (T::*pmethod)( Data* pd ) ) {
cout << " calling any method\n";
Data d;
(pthis->*pmethod)( &d ); // <-- PROBLEMATIC LINE
}
// Inside methods of class Foo:
SubscribeTimer( "14:59:50", this, &Foo::TimerDone );
所以... 胜利!这是我想要的更简单的语法,而不是上面显示的更混乱的 lambda 和 std::bind
。
但这是我的问题。 上面的示例之所以有效,是因为标记为 PROBLEMATIC LINE 的行位于编译器知道 pthis
类型的上下文中。但实际上,SubscribeTimer()
不会立即调用该回调。相反,它会保存该值以供将来参考。很久以后,如果应用程序仍然 运行 在 14:59:50,将调用该回调。
你已经知道答案的所有部分(std::function
,lambdas);你只需要把它们放在一起。
std::function<void(Data*)> f = [=](Data* d) { (pthis->*pmethod)(d); }
现在保存这个功能,例如在数据成员中。到调用的时候,就是
Data d;
f_member(&d);
问题:我有一个模板函数,它接受模板参数 class 的对象指针和指向 class 的方法的方法指针。然后我可以立即对该对象调用该方法。但我不想立即调用它。相反,我想保存这两个指针以供将来使用,并在以后的代码中调用它们,而这些代码不会根据上下文知道该类型是什么。
在遗留 C/C++99 代码中,我们将一个函数指针和一个 void*
用户数据指针传递给将执行回调的代码(例如,在计时器完成时,用户事件等)我们几乎总是传入一个对象指针作为用户数据,并编写一个单行 C 函数,将用户数据指针转换为该类型并调用该对象的方法:
void TimerCB( void* pvUserData, void* pvCallerData ) {
( (Foo*) pvUserData )->TimerDone( pvCallerData );
}
在 C++11 中,std::function
让我们可以传入 lambda 和 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 );} );
我可以传入方法指针,如果我在编译时知道他们对象的class,就像这样:
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 );
但是,这是不可接受的,因为我的计时器 class 是项目的实用程序库级别,不需要像 Foo 这样的每个可能的用户 class 都知道.
好的,事实证明我可以将该方法模板化,因此我不再需要知道 Foo 是什么类型的对象或该方法是什么方法。这编译没有错误。 (方法和 class 指针交换,因此很清楚调用了哪个重载函数。)
class Timer {
:
template<typename T> void SubscribeTimer( const char* pszTime, T* pthis,
void (T::*pfn)( Data* pd ) );
};
template<typename T> void Foo::SubscribeTimer( const char* pszTime, T* pthis,
void (T::*pmethod)( Data* pd ) ) {
cout << " calling any method\n";
Data d;
(pthis->*pmethod)( &d ); // <-- PROBLEMATIC LINE
}
// Inside methods of class Foo:
SubscribeTimer( "14:59:50", this, &Foo::TimerDone );
所以... 胜利!这是我想要的更简单的语法,而不是上面显示的更混乱的 lambda 和 std::bind
。
但这是我的问题。 上面的示例之所以有效,是因为标记为 PROBLEMATIC LINE 的行位于编译器知道 pthis
类型的上下文中。但实际上,SubscribeTimer()
不会立即调用该回调。相反,它会保存该值以供将来参考。很久以后,如果应用程序仍然 运行 在 14:59:50,将调用该回调。
你已经知道答案的所有部分(std::function
,lambdas);你只需要把它们放在一起。
std::function<void(Data*)> f = [=](Data* d) { (pthis->*pmethod)(d); }
现在保存这个功能,例如在数据成员中。到调用的时候,就是
Data d;
f_member(&d);