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

时间:2018-08-06 11:38:36

标签: c++ c++11 overloading sfinae perfect-forwarding

我正在开发一种用于创建“安全”回调的机制,该回调在其父对象被销毁后调用时不会引起未定义的行为。该类应具有足够的通用性,以便能够包装任何回调,并根据它们所绑定的对象的状态,简单地执行是否执行void(...)回调,以及返回值返回boost的回调::可选,如果执行则返回值;如果未执行则返回boost :: none。实现几乎完成,但是有两件事让我担心我不完全了解我的代码...

如果第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;

}

2 个答案:

答案 0 :(得分:3)

注意:这只能回答第一个问题,因为我显然注意力集中。更多即将推出。


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

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

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

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

这会将Argsargs扩展为一组,然后在函子样式强制转换为{ {1}}。整个过程都是表达式,而不是,期望的类型。

您似乎正要使用Func的一半,它看起来像:

std::result_of

...,或者,如果您不愿意将其移动到decltype的声明下:

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

答案 1 :(得分:0)

超载规则就是这样。

功能的签名应该不同。

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