ScopeGuard

#include <iostream>
#include <functional>

template <typename FunT>
class ScopeGuard
{
public:
    ScopeGuard() = delete;

    ScopeGuard(const ScopeGuard &) = delete;
    ScopeGuard &operator=(const ScopeGuard &) = delete;

    ScopeGuard(ScopeGuard &&rhs) : fun_(std::move(rhs.fun_)), activate_(true)
    {
        rhs.activate_ = false;
    };

    ScopeGuard &operator=(ScopeGuard &&rhs)
    {
        if (this == &rhs)
        {
            return *this;
        }

        fun_ = std::move(rhs.fun_);
        activate_ = true;

        rhs.activate_ = false;

        return *this;
    }

    // Accept lvalue function objects
    ScopeGuard(const FunT &f) : fun_(f),
                                activate_(true)
    {
        std::cout << "called ScopeGuard(const FunT &f)" << std::endl;
    }

    // Accept rvalue function objects
    ScopeGuard(FunT &&f) : fun_(std::move(f)),
                           activate_(true)
    {
        std::cout << "called ScopeGuard(FunT &&f)" << std::endl;
    }

    ~ScopeGuard()
    {
        if (activate_)
        {
            fun_();
        }
    }

private:
    FunT fun_;
    bool activate_ = false;
};

template <typename F>
ScopeGuard<typename std::decay<F>::type> MakeScopeGuard(F &&f)
{
    return ScopeGuard<typename std::decay<F>::type>(std::forward<F>(f));
}

void print()
{
    std::cout << "void print()" << std::endl;
}


struct StrcutFun
{
    void operator()()
    {
        std::cout << "void operator()()" << std::endl;
    }
};

int main(int argc, char *argv[])
{

    ScopeGuard([]()
               { std::cout << "[] () {}" << std::endl; });
    MakeScopeGuard([]()
                   { std::cout << "[] () {}" << std::endl; });

    // ScopeGuard(print); //  error: class template argument deduction failed
    // ScopeGuard<typename std::decay<decltype(print)>::type>(std::ref(print));
    // ScopeGuard<typename std::decay<decltype(print)>::type>([](auto &fun)
    //                                                        { return fun; }(print));
    MakeScopeGuard(print);

    ScopeGuard(std::function<void()>{[]()
                                     { std::cout << "std::function<void()>" << std::endl; }});
    MakeScopeGuard(std::function<void()>{[]()
                                         { std::cout << "std::function<void()>" << std::endl; }});

    ScopeGuard(StrcutFun{});
    MakeScopeGuard(StrcutFun{});

    const StrcutFun str_fn;
    // error: conflicting declaration ‘ScopeGuard<...auto...> str_fn’
    // ScopeGuard(str_fn);
    MakeScopeGuard(str_fn);

    return EXIT_SUCCESS;
}
// called ScopeGuard(FunT &&f)
// [] () {}
// called ScopeGuard(FunT &&f)
// [] () {}
// called ScopeGuard(FunT &&f)
// void print()
// called ScopeGuard(FunT &&f)
// std::function<void()>
// called ScopeGuard(FunT &&f)
// std::function<void()>
// called ScopeGuard(FunT &&f)
// void operator()()
// called ScopeGuard(FunT &&f)
// void operator()()
// called ScopeGuard(const FunT &f)
// void operator()()

为什么不能直接使用

ScopeGuard(print);

使用头文件typeinfo查看两个的类型区别

std::cout << typeid(print).name() << std::endl;
// FvvE, 函数类型

std::cout << typeid(std::decay<decltype(print)>::type).name() << std::endl;
// PFvvE,函数指针类型

可见,传递给ScopeGuard应该是函数指针,于是可

ScopeGuard<typename std::decay<decltype(print)>::type>(print);
// error: use of deleted function ‘ScopeGuard<FunT>::ScopeGuard() [with FunT = void (*)()]’
// ScopeGuard<typename std::decay<decltype(print)>::type>(print);

先使用decltype对函数print获取其类型,再退化成函数指针,作为ScopeGuard的类型。然而依然保存,这是因为没有和

ScopeGuard(FunT &&f);

匹配上。

有两种方法,一是使用std::ref显示引用函数

ScopeGuard<typename std::decay<decltype(print)>::type>(std::ref(print));
// called ScopeGuard(FunT &&f)
// void print()

也可以是使用一个函数模拟转发

// ‘[](auto &fun) { return fun; }’ is a lambda function
ScopeGuard<typename std::decay<decltype(print)>::type>([](auto &fun)
                                                           { return fun; }(print));
// called ScopeGuard(FunT &&f)
// void print()   

Ref.

  1. https://crascit.com/2015/06/03/on-leaving-scope-part-2/
  2. https://www.cnblogs.com/qicosmos/p/3421333.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值