安全回调提供程序(SFINAE,std::forward 和重载解析)

Safe Callback Provider (SFINAE, std::forward and overload resolution)

我正在研究一种创建 "safe" 回调的机制,在其父对象被销毁后调用时不会导致未定义的行为。 class 应该足够通用以能够包装任何回调,void(...) 回调只是被执行或不被执行,这取决于它们绑定到的对象的状态,以及 return 一个值 return 一个 boost::optional 与 returned 值,如果被执行,或者 boost::none 如果没有 executed.The 实现几乎完成,但是有有两件事让我担心我没有完全理解我的代码...

如果第 19 行未注释掉并且第 18 行被注释掉,模板将无法编译 - 这仅仅是一个可以解决的语法问题,还是我试图错误地使用 result_of 机制(是否std::forward 语义有变化还是多余?)

如果第 88 行未注释掉,第 89 行被注释掉,则由于函数调用 fun 的歧义导致编译失败,我不太明白 - 在我看来 fun(int&&) 是一个确切的匹配,那么为什么编译器会抱怨 fun(int) 版本不明确?

如果还有其他细微(或严重)错误,请一并评论。

谢谢。

#include <iostream>
#include <string>
#include <type_traits>
#include <utility>
#include <memory>
#include <boost/optional.hpp>

template<class Func>
class SafeCallback
{
public:
    SafeCallback(std::shared_ptr<bool> guard, const Func& callback)
        : guard_(guard)
        , callback_(callback)
    {}

    template<class... Args>
    // auto operator()(Args&&... args) -> typename std::enable_if<std::is_void<typename std::result_of<Func(std::forward<Args>(args)...)>::type>::value,  //  won't compile with: 19:91: error: invalid use of template-name 'std::result_of' without an argument list
    auto operator()(Args&&... args) -> typename std::enable_if<std::is_void<typename std::result_of<Func(Args...)>::type>::value,
                                                               void>::type
    {
        std::cout << "trying void callback" << std::endl;
        if(guard_.lock())
        {
            std::cout << "callback is still alive :)" << std::endl;
            callback_(std::forward<Args>(args)...);
            return;
        }
        std::cout << "uh-oh, callback is dead!" << std::endl;
    }

    template<class... Args>
    auto operator()(Args&&... args) -> typename std::enable_if<!std::is_void<typename std::result_of<Func(Args...)>::type>::value,
                                                               boost::optional<typename std::result_of<Func(Args...)>::type>>::type
    {
        std::cout << "trying non-void callback" << std::endl;
        if(guard_.lock())
        {
            std::cout << "callback is still alive :)" << std::endl;
            return callback_(std::forward<Args>(args)...);
        }
        std::cout << "uh-oh, callback is dead!" << std::endl;
        return boost::none;
    }

    bool isAlive()
    {
        return guard_.lock();
    }

private:  
    std::weak_ptr<bool> guard_;
    Func callback_;
};

class SafeCallbackProvider
{
public:
    SafeCallbackProvider()
        : guard_(new bool(true))
    {}

    virtual ~SafeCallbackProvider() = default;

    template<class Func>
    SafeCallback<Func> makeSafeCallback(const Func& callback)
    {
        return SafeCallback<Func>(guard_, callback);
    }

private:
    std::shared_ptr<bool> guard_;
};

struct A : SafeCallbackProvider
{
    void fun()
    {
        std::cout << "---this is fun---" << std::endl;
    }

    int fun(int&& i)
    {
        std::cout << "&& this is && " << i << " && fun &&" << std::endl;
        return i;
    }

    // int fun(int i) // fails to compile with: 123:48: error: call of overloaded 'fun(int)' is ambiguous
    int fun(int& i)
    {
        std::cout << "---this is ---" << i << "--- fun---" << std::endl;
        return i;
    }
};

int main()
{
    A* a= new A;
    auto cb = a->makeSafeCallback(
        [&]()
        {
            a->fun();
        });
    cb();
    delete a;
    cb();

    std::cout << "\n----------\n\n";

    A* a2= new A;
    auto cb2 = a2->makeSafeCallback(
        [&](int i)
        {
            return a2->fun(i);
        });
    cb2(5);
    delete a2;
    cb2(5);

    std::cout << "\n----------\n\n";

    A* a3= new A;
    auto cb3 = a3->makeSafeCallback(
        [&](int&& i)
        {
            return a3->fun(std::forward<int>(i));
        });
    cb3(5);
    delete a3;
    cb3(5);
    return 0;

}

重载的规则是。

函数签名应该不同。

在这两种情况下,编译器都找到相同的签名,尝试更改签名并查看结果。

注意:这只回答了第一个问题,因为我显然有一只苍蝇的注意力。更多即将推出。


std::result_of 本质上是基于看起来像函数 call 的函数 type 执行一些魔法。在有效的行中:

typename std::result_of<Func(Args...)>::type

这是预期用途,模拟调用具有类型 Args... 值的 Func 的实例。另一方面:

typename std::result_of<Func(std::forward<Args>(args)...)>::type

这会将 Argsargs 扩展为一组 ,然后在函数内形成一个 , 运算符链-style 转换为 Func。整个事情是一个表达式而不是 std::result_of 期望的类型。

您似乎已经中途使用 decltype,它看起来像:

decltype(std::declval<Func&>()(std::forward<Args>(args)...))

... 或者,如果您不厌其烦地将它移到 callback_ 的声明下方:

decltype(callback_(std::forward<Args>(args)...))