CppCoreGuidelines里面的finally
这种写法的主要设计思想:
1、使用模板参数typename A指示lambda表达式的类型,不使用std::function,避免std::function过于重量级的问题,不需要依赖任何标准库设施;
2、使用函数模板自动推导出类模板里的typename A,因为类模板(在C++17之前)不能自动推导模板参数。
template<typename A>
struct final_action { // slightly simplified
A act;
final_action(A a) :act{a} {}
~final_action() { act(); }
};
template<typename A>
final_action<A> finally(A act) // deduce action type
{
return final_action<A>{act};
}
void test()
{
auto act = finally([]{ cout << "Exit test\n"; }); // establish exit action
// ...
if (something) return; // act done here
// ...
} // act done here
实际上C++17以后已经不需要函数模板了,直接类模板就可以推导模板参数了:
template<typename A>
struct final_action { // slightly simplified
A act;
final_action(A a) :act{a} {}
~final_action() { act(); }
};
void test()
{
auto act = final_action([]{ cout << "Exit test\n"; }); // establish exit action
// ...
if (something) return; // act done here
// ...
} // act done here
完整版在microsoft/GSL里面,这个GSL代码库可以下载下来直接使用。
https://github.com/microsoft/GSL/blob/master/include/gsl/gsl_util
下面是代码节选,可以看出来它主要完善了复制和移动操作的相关内容:
1、移动构造被保留,用于支持从右值构造的语法;
2、复制构造被删除,用于防止finally被执行两次以上;
3、赋值运算符被删除,带捕获的lambda表达式只可构造,不可赋值;
4、使用bool invoke_标记避免调用已经被移走的lambda表达式;
5、添加了一些noexcept标记;
6、GSL_SUPPRESS是用来关闭某些CppCoreCheck建议的,可以直接注释掉。
// final_action allows you to ensure something gets run at the end of a scope
template <class F>
class final_action
{
public:
explicit final_action(F f) noexcept : f_(std::move(f)) {}
final_action(final_action&& other) noexcept : f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false)) {}
final_action(const final_action&) = delete;
final_action& operator=(const final_action&) = delete;
final_action& operator=(final_action&&) = delete;
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws
~final_action() noexcept
{
if (invoke_) f_();
}
private:
F f_;
bool invoke_{true};
};
// finally() - convenience function to generate a final_action
template <class F>
final_action<F> finally(const F& f) noexcept
{
return final_action<F>(f);
}
template <class F>
final_action<F> finally(F&& f) noexcept
{
return final_action<F>(std::forward<F>(f));
}