@@ -36,7 +36,7 @@ namespace beman::scope {
3636// private:
3737// EF exit_function; // exposition only
3838// bool execute_on_destruction{true}; // exposition only
39- // int uncaught_on_creation {uncaught_exceptions()}; // exposition only
39+ // int m_uncaught_on_creation {uncaught_exceptions()}; // exposition only
4040// };
4141//
4242// template <class EF>
@@ -45,61 +45,91 @@ namespace beman::scope {
4545
4646// =========================================================
4747
48+ template <typename T>
49+ concept HasCanInvoke = requires (T t) {
50+ { t.can_invoke () } -> std::convertible_to<bool >;
51+ };
52+
53+ template <typename T>
54+ concept HasStaticCanInvoke = requires {
55+ { T::can_invoke () } -> std::convertible_to<bool >;
56+ };
57+
58+ template <typename T>
59+ concept HasRelease = requires (T t) {
60+ { t.release () } -> std::same_as<void >;
61+ };
62+
63+ template <typename T>
64+ concept HasStaticRelease = requires {
65+ { T::release () } -> std::same_as<void >;
66+ };
67+
4868template <typename F, typename R, typename ... Args>
4969concept invocable_return = std::invocable<F, Args...> && std::same_as<std::invoke_result_t <F, Args...>, R>;
5070
71+ template <typename T>
72+ concept scope_invoke_checker = HasStaticCanInvoke<T> || HasCanInvoke<T> || invocable_return<T, bool >;
73+
5174// =========================================================
5275
5376struct ExecuteAlways ;
5477
5578// =========================================================
5679
57- template <invocable_return<void > ExitFunc, invocable_return< bool > ExecuteCondition = ExecuteAlways>
58- class scope_guard {
80+ template <invocable_return<void > ExitFunc, scope_invoke_checker InvokeChecker = ExecuteAlways>
81+ class scope_guard : public InvokeChecker {
5982 public:
60- explicit scope_guard (ExitFunc&& func) /* noexcept(see below)*/
61- : m_exit_func(std::move(func)) //
83+ explicit scope_guard (ExitFunc&& exit_func) /* noexcept(see below)*/
84+ : m_exit_func(std::move(exit_func)) //
85+ {}
86+
87+ explicit scope_guard (ExitFunc&& exit_func, InvokeChecker&& invoke_checker) /* noexcept(see below)*/
88+ : m_exit_func(std::move(exit_func)),
89+ m_invoke_checker{std::move (invoke_checker)} //
6290 {}
6391
64- scope_guard (scope_guard&& rhs) noexcept
65- : m_exit_func{std::move (rhs)}, m_invoke_condition_func{std::move (rhs.m_invoke_condition_func )} {}
92+ explicit scope_guard (scope_guard&& rhs) noexcept
93+ : m_exit_func{std::move (rhs)},
94+ m_invoke_checker{std::move (rhs.m_invoke_checker )} //
95+ {}
6696
6797 scope_guard (const scope_guard&) = delete ;
6898 scope_guard& operator =(const scope_guard&) = delete ;
6999 scope_guard& operator =(scope_guard&&) = delete ;
70100
71101 ~scope_guard () /* noexcept(see below)*/ {
72- if (can_invoke_check (m_invoke_condition_func )) {
102+ if (can_invoke_check (m_invoke_checker )) {
73103 m_exit_func ();
74104 }
75105 }
76106
77- void release () noexcept {
78- // Needs implementation
107+ void release () noexcept
108+ requires HasRelease<InvokeChecker> || HasStaticRelease<InvokeChecker>
109+ {
110+ if constexpr (HasRelease<InvokeChecker>) {
111+ m_invoke_checker.release ();
112+ } else {
113+ InvokeChecker::release ();
114+ }
79115 }
80116
81117 private:
82- ExitFunc m_exit_func;
83- [[no_unique_address]] ExecuteCondition m_invoke_condition_func ;
118+ ExitFunc m_exit_func;
119+ [[no_unique_address]] InvokeChecker m_invoke_checker ;
84120
85121 template <typename T>
86- bool can_invoke_check (const T& obj) const {
87- if constexpr (requires (T /* t*/ ) {
88- { T::can_invoke () } -> std::convertible_to<bool >;
89- }) {
122+ static bool can_invoke_check (const T& obj) {
123+ if constexpr (HasStaticCanInvoke<T>) {
90124 return T::can_invoke ();
91- } else if constexpr (requires (T t) {
92- { t.can_invoke () } -> std::convertible_to<bool >;
93- }) {
125+ } else if constexpr (HasCanInvoke<T>) {
94126 return obj.can_invoke ();
95- } else if constexpr (requires {
96- { T::operator ()() } -> std::convertible_to<bool >;
97- }) {
98- return T::operator ()();
99- } else if constexpr (requires (T t) {
100- { t.operator ()() } -> std::convertible_to<bool >;
101- }) {
102- return obj ();
127+ } else if constexpr (invocable_return<T, bool >) {
128+ return std::invoke (obj);
129+ // } else if constexpr (HasStaticParenthesisOperator<T>) {
130+ // return T::operator()();
131+ // } else if constexpr (HasParenthesisOperator<T>) {
132+ // return obj();
103133 } else {
104134 return true ; // Default behavior if no check function is available
105135 }
@@ -109,54 +139,90 @@ class scope_guard {
109139// =========================================================
110140
111141template <std::invocable ExitFunc>
112- scope_guard (ExitFunc) -> scope_guard<ExitFunc>;
113-
114- // =========================================================
142+ scope_guard (ExitFunc&&) -> scope_guard<ExitFunc>;
115143
116- // -- 7.5.1 Header <scope> synopsis [scope.syn] --
117- //
118- // namespace std {
119- // template <class EF>
120- // class scope_exit;
121- //
122- // template <class EF>
123- // class scope_fail;
124- //
125- // template <class EF>
126- // class scope_success;
144+ template <std::invocable ExitFunc, scope_invoke_checker InvokeChecker>
145+ scope_guard (ExitFunc&&, InvokeChecker&&) -> scope_guard<ExitFunc, InvokeChecker>;
127146
147+ // =========================================================
148+ // =========================================================
128149// =========================================================
129150
130151struct ExecuteAlways {
131- [[nodiscard]] constexpr bool operator ()() const { return true ; }
152+ [[nodiscard]] static constexpr bool can_invoke () { return true ; }
153+ };
154+
155+ class ExecuteWhenNoException {
156+ public:
157+ [[nodiscard]] bool can_invoke () const { return m_uncaught_on_creation >= std::uncaught_exceptions (); }
158+
159+ private:
160+ int m_uncaught_on_creation = std::uncaught_exceptions();
132161};
133162
134- struct ExecuteWhenNoException {
163+ class ExecuteOnlyWhenException {
164+ public:
165+ [[nodiscard]] bool can_invoke () const { return m_uncaught_on_creation < std::uncaught_exceptions (); }
135166
136- [[nodiscard]] bool operator ()() const { return uncaught_on_creation >= std::uncaught_exceptions (); }
167+ private:
168+ int m_uncaught_on_creation = std::uncaught_exceptions();
169+ };
170+
171+ // =========================================================
172+
173+ template <typename T = void >
174+ class Releasable ;
175+
176+ template <>
177+ class Releasable <void > {
178+ public:
179+ bool can_invoke () const { return m_can_invoke; }
180+
181+ void release () { m_can_invoke = false ; }
137182
138183 private:
139- int uncaught_on_creation = std::uncaught_exceptions() ;
184+ bool m_can_invoke = true ;
140185};
141186
142- struct ExecuteOnlyWhenException {
187+ template <scope_invoke_checker InvokeChecker>
188+ class Releasable <InvokeChecker> : private InvokeChecker {
189+ public:
190+ Releasable () = default ;
191+
192+ Releasable (InvokeChecker&& invoke_checker) : InvokeChecker(std::move(invoke_checker)) {}
143193
144- [[nodiscard]] bool operator ()() const { return uncaught_on_creation < std::uncaught_exceptions (); }
194+ bool can_invoke () const { return m_can_invoke && static_cast <const InvokeChecker*>(this )->can_invoke (); }
195+
196+ void release () { m_can_invoke = false ; }
145197
146198 private:
147- int uncaught_on_creation = std::uncaught_exceptions() ;
199+ bool m_can_invoke = true ;
148200};
149201
150202// =========================================================
151203
204+ // -- 7.5.1 Header <scope> synopsis [scope.syn] --
205+ //
206+ // namespace std {
207+ // template <class EF>
208+ // class scope_exit;
209+ //
210+ // template <class EF>
211+ // class scope_fail;
212+ //
213+ // template <class EF>
214+ // class scope_success;
215+
216+ // =========================================================
217+
152218template <class ExitFunc >
153- using scope_exit = scope_guard<ExitFunc>;
219+ using scope_exit = scope_guard<ExitFunc, Releasable<> >;
154220
155221template <class ExitFunc >
156- using scope_success = scope_guard<ExitFunc, ExecuteWhenNoException>;
222+ using scope_success = scope_guard<ExitFunc, Releasable< ExecuteWhenNoException> >;
157223
158224template <class ExitFunc >
159- using scope_fail = scope_guard<ExitFunc, ExecuteOnlyWhenException>;
225+ using scope_fail = scope_guard<ExitFunc, Releasable< ExecuteOnlyWhenException> >;
160226
161227// =========================================================
162228
0 commit comments