使用带参数包的成员函数指针

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)...);
        }
    };
}