/* * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * https://www.boost.org/LICENSE_1_0.txt) * * Copyright (c) 2022-2024 Andrey Semashev */ /*! * \file scope/defer.hpp * * This header contains definition of \c defer_guard template. */ #ifndef BOOST_SCOPE_DEFER_HPP_INCLUDED_ #define BOOST_SCOPE_DEFER_HPP_INCLUDED_ #include #include #include #include #include #include #include #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once #endif namespace boost { namespace scope { template< typename Func > class defer_guard; namespace detail { // Workaround for clang < 5.0 which can't pass defer_guard as a template template parameter from within defer_guard definition template< typename T > using is_not_like_defer_guard = detail::is_not_like< T, defer_guard >; } // namespace detail /*! * \brief Defer guard that invokes a function upon leaving the scope. * * The scope guard wraps a function object callable with no arguments * that can be one of: * * \li A user-defined class with a public `operator()`. * \li An lvalue reference to such class. * \li An lvalue reference or pointer to function taking no arguments. * * The defer guard unconditionally invokes the wrapped function object * on destruction. */ template< typename Func > class defer_guard { //! \cond private: struct data { Func m_func; template< typename F, typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type > explicit data(F&& func, std::true_type) noexcept : m_func(static_cast< F&& >(func)) { } template< typename F, typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type > explicit data(F&& func, std::false_type) try : m_func(static_cast< F&& >(func)) { } catch (...) { func(); } }; data m_data; //! \endcond public: /*! * \brief Constructs a defer guard with a given callable function object. * * **Requires:** \c Func is constructible from \a func. * * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from * `std::forward< F >(func)`, otherwise constructs from `func`. * * If \c Func construction throws, invokes \a func before returning with the exception. * * **Throws:** Nothing, unless construction of the function object throws. * * \param func The callable function object to invoke on destruction. */ template< typename F //! \cond , typename = typename std::enable_if< detail::conjunction< std::is_constructible< data, typename detail::move_or_copy_construct_ref< F, Func >::type, typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type >, detail::is_not_like_defer_guard< F > >::value >::type //! \endcond > defer_guard(F&& func) noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN( std::is_nothrow_constructible< data, typename detail::move_or_copy_construct_ref< F, Func >::type, typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type >::value )) : m_data ( static_cast< typename detail::move_or_copy_construct_ref< F, Func >::type >(func), typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type() ) { } defer_guard(defer_guard const&) = delete; defer_guard& operator= (defer_guard const&) = delete; /*! * \brief Invokes the wrapped callable function object and destroys the callable. * * **Throws:** Nothing, unless invoking the callable throws. */ ~defer_guard() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_invocable< Func& >::value)) { m_data.m_func(); } }; #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) template< typename Func > defer_guard(Func) -> defer_guard< Func >; #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES) } // namespace scope //! \cond #if defined(BOOST_MSVC) #define BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG __COUNTER__ #else #define BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG __LINE__ #endif //! \endcond /*! * \brief The macro creates a uniquely named defer guard. * * The macro should be followed by a function object that should be called * on leaving the current scope. Usage example: * * ``` * BOOST_SCOPE_DEFER [] * { * std::cout << "Hello world!" << std::endl; * }; * ``` * * \note Using this macro requires C++17. */ #define BOOST_SCOPE_DEFER \ boost::scope::defer_guard BOOST_JOIN(_boost_defer_guard_, BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG) = } // namespace boost #include #endif // BOOST_SCOPE_DEFER_HPP_INCLUDED_