#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.
- https://crascit.com/2015/06/03/on-leaving-scope-part-2/
- https://www.cnblogs.com/qicosmos/p/3421333.html