使用带参数包的成员函数指针
Using member-function-pointer with parameter-pack
template<typename Callback, typename Callee, typename... Args>
std::function<void(Args...)> safe_bind(Callback callback, std::shared_ptr<Callee> shared) {
std::weak_ptr<Callee> weak = shared;
return std::function<void(Args...)>([callback, weak](Args... args){
if(auto shared_ptr = weak.lock()) {
// std::bind(callback, ptr)(args...);
// callback(ptr, args...);
(shared_ptr.get()->*callback)(args...);
}
});
}
此函数类似于std::bind
,但返回的函数在绑定对象被销毁时可以安全调用。
它无法编译,因为无法推导出 Args
。我要联想Callback = void(Args...)
。但是我找不到用 std::function 或带有参数包的函数指针类型替换 Callback
的方法。
safe_bind(Callback callback, std::shared_ptr<Callee> shared) { // does not compile
safe_bind(void(*)(Callee*, Args...) callback, std::shared_ptr<Callee> shared) { // does not compile
safe_bind((void(*)(Callee*, Args...)) callback, std::shared_ptr<Callee> shared) {// does not compile
...
如何实现?
callback
将主要是 &Class::method
,因此最好(如果可能)不使用 std::function
的解决方案来避免分配。
只是不要将 lambda 包装在 std::function
中并使用任何参数类型的完美转发。您还可以使用 std::invoke
处理其他可调用对象,它会自动处理指向成员(函数)的指针、函数和带有 operator()
:
的对象
template<typename Callback, typename Callee>
auto safe_bind(Callback&& callback, std::shared_ptr<Callee> shared) {
return [weak = std::weak_ptr{shared}, callback = std::forward<Callback>(callback)](auto&&... args) {
if (auto shared_ptr = weak.lock()) {
std::invoke(callback, *shared_ptr, std::forward<decltype(args)>(args)...);
}
};
}
如果函数始终是指向成员函数的指针,您可以从指针推断出参数的类型:
template<typename Callee, typename Res, typename... Args>
auto safe_bind(Res (Callee::* callback)(Args...), std::shared_ptr<Callee> shared) {
return [weak = std::weak_ptr<Callee>{shared}, callback](Args... args) {
if (auto shared_ptr = weak.lock()) {
// The std::forward here moves arguments that are passed by value
((*shared_ptr).*callback)(std::forward<Args>(args)...);
}
};
}
template<typename Callback, typename Callee, typename... Args>
std::function<void(Args...)> safe_bind(Callback callback, std::shared_ptr<Callee> shared) {
std::weak_ptr<Callee> weak = shared;
return std::function<void(Args...)>([callback, weak](Args... args){
if(auto shared_ptr = weak.lock()) {
// std::bind(callback, ptr)(args...);
// callback(ptr, args...);
(shared_ptr.get()->*callback)(args...);
}
});
}
此函数类似于std::bind
,但返回的函数在绑定对象被销毁时可以安全调用。
它无法编译,因为无法推导出 Args
。我要联想Callback = void(Args...)
。但是我找不到用 std::function 或带有参数包的函数指针类型替换 Callback
的方法。
safe_bind(Callback callback, std::shared_ptr<Callee> shared) { // does not compile
safe_bind(void(*)(Callee*, Args...) callback, std::shared_ptr<Callee> shared) { // does not compile
safe_bind((void(*)(Callee*, Args...)) callback, std::shared_ptr<Callee> shared) {// does not compile
...
如何实现?
callback
将主要是 &Class::method
,因此最好(如果可能)不使用 std::function
的解决方案来避免分配。
只是不要将 lambda 包装在 std::function
中并使用任何参数类型的完美转发。您还可以使用 std::invoke
处理其他可调用对象,它会自动处理指向成员(函数)的指针、函数和带有 operator()
:
template<typename Callback, typename Callee>
auto safe_bind(Callback&& callback, std::shared_ptr<Callee> shared) {
return [weak = std::weak_ptr{shared}, callback = std::forward<Callback>(callback)](auto&&... args) {
if (auto shared_ptr = weak.lock()) {
std::invoke(callback, *shared_ptr, std::forward<decltype(args)>(args)...);
}
};
}
如果函数始终是指向成员函数的指针,您可以从指针推断出参数的类型:
template<typename Callee, typename Res, typename... Args>
auto safe_bind(Res (Callee::* callback)(Args...), std::shared_ptr<Callee> shared) {
return [weak = std::weak_ptr<Callee>{shared}, callback](Args... args) {
if (auto shared_ptr = weak.lock()) {
// The std::forward here moves arguments that are passed by value
((*shared_ptr).*callback)(std::forward<Args>(args)...);
}
};
}