#pragma once #include #include namespace ext { template class [[nodiscard]] basic_scope_guard { public: constexpr basic_scope_guard() = default; constexpr basic_scope_guard(basic_scope_guard && src) : function{std::exchange(src.function, F{})} {} constexpr basic_scope_guard & operator=(basic_scope_guard && src) { if (this != &src) { invoke(); function = std::exchange(src.function, F{}); } return *this; } template , void>> constexpr basic_scope_guard(const G & function_) : function{function_} {} template , void>> constexpr basic_scope_guard(G && function_) : function{std::move(function_)} {} ~basic_scope_guard() { invoke(); } private: void invoke() { if constexpr (std::is_constructible_v) { if (!function) return; } function(); } F function = F{}; }; using scope_guard = basic_scope_guard>; template inline basic_scope_guard make_scope_guard(F && function_) { return std::forward(function_); } } #define SCOPE_EXIT_CONCAT(n, ...) \ const auto scope_exit##n = ext::make_scope_guard([&] { __VA_ARGS__; }) #define SCOPE_EXIT_FWD(n, ...) SCOPE_EXIT_CONCAT(n, __VA_ARGS__) #define SCOPE_EXIT(...) SCOPE_EXIT_FWD(__LINE__, __VA_ARGS__)