Skip to content

Commit 40629b1

Browse files
fixes
1 parent e9533d3 commit 40629b1

File tree

2 files changed

+208
-60
lines changed

2 files changed

+208
-60
lines changed

include/beman/scope/scope.hpp

Lines changed: 133 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,39 @@ class NeverExecute;
107107

108108
//==================================================================================================
109109

110+
//Template argument `ScopeExitFunc` shall be
111+
// - a function object type([function.objects]),
112+
// - lvalue reference to function,
113+
// - or lvalue reference to function object type.
114+
//
115+
// If `ScopeExitFunc` is an object type, it shall meet the requirements of Cpp17Destructible(Table 30).
116+
// Given an lvalue g of type remove_reference_t<EF>, the expression g() shall be well- formed.
117+
118+
110119
template<scope_exit_function ScopeExitFunc, scope_invoke_checker InvokeChecker = ExecuteAlways>
111120
class [[nodiscard]] scope_guard
112121
{
113122
public:
123+
//The constructor parameter `exit_func` in the following constructors shall be :
124+
// - a reference to a function
125+
// - or a reference to a function object([function.objects])
126+
//
127+
128+
// If EFP is not an lvalue reference type and is_nothrow_constructible_v<EF,EFP> is true,
129+
// initialize exit_function with std::forward<EFP>(f);
130+
// otherwise initialize exit_function with f.
131+
132+
// scope_fail / scope_exit
133+
// If the initialization of exit_function throws an exception, calls f().
134+
135+
// scope_success
136+
// [Note: If initialization of exit_function fails, f() won’t be called. —end note]
137+
114138
template<typename T, typename S>
115139
explicit constexpr scope_guard(T&& exit_func, S&& invoke_checker)
116140
noexcept(std::is_nothrow_constructible_v<ScopeExitFunc> && std::is_nothrow_constructible_v<InvokeChecker>)
141+
requires (std::is_lvalue_reference_v<T> && std::is_nothrow_constructible_v<ScopeExitFunc, T>
142+
&& std::is_lvalue_reference_v<S> && std::is_nothrow_constructible_v<InvokeChecker, S>)
117143
try
118144
: m_exit_func(std::forward<T>(exit_func)),
119145
m_invoke_checker{ std::forward<S>(invoke_checker) }
@@ -132,12 +158,100 @@ class [[nodiscard]] scope_guard
132158
}
133159

134160

161+
template<typename T, typename S>
162+
explicit constexpr scope_guard(T&& exit_func, S&& invoke_checker)
163+
noexcept(std::is_nothrow_constructible_v<ScopeExitFunc> && std::is_nothrow_constructible_v<InvokeChecker>)
164+
requires (std::is_lvalue_reference_v<T> && std::is_nothrow_constructible_v<ScopeExitFunc, T>
165+
&& ( !std::is_lvalue_reference_v<S> || !std::is_nothrow_constructible_v<InvokeChecker, S> ))
166+
try
167+
: m_exit_func(std::forward<T>(exit_func)),
168+
m_invoke_checker{ invoke_checker }
169+
{}
170+
catch (...)
171+
{
172+
if constexpr (!std::is_nothrow_constructible_v<ScopeExitFunc>)
173+
{
174+
if constexpr (!HasDontInvokeOnCreationException<ScopeExitFunc>)
175+
{
176+
exit_func();
177+
}
178+
179+
throw;
180+
}
181+
}
182+
183+
184+
template<typename T, typename S>
185+
explicit constexpr scope_guard(T&& exit_func, S&& invoke_checker)
186+
noexcept(std::is_nothrow_constructible_v<ScopeExitFunc> && std::is_nothrow_constructible_v<InvokeChecker>)
187+
requires ((!std::is_lvalue_reference_v<T> || !std::is_nothrow_constructible_v<ScopeExitFunc, T>)
188+
&& std::is_lvalue_reference_v<S> && std::is_nothrow_constructible_v<InvokeChecker, S>)
189+
try
190+
: m_exit_func(exit_func),
191+
m_invoke_checker{ std::forward<S>(invoke_checker) }
192+
{}
193+
catch (...)
194+
{
195+
if constexpr (!std::is_nothrow_constructible_v<ScopeExitFunc>)
196+
{
197+
if constexpr (!HasDontInvokeOnCreationException<ScopeExitFunc>)
198+
{
199+
exit_func();
200+
}
201+
202+
throw;
203+
}
204+
}
205+
206+
template<typename T, typename S>
207+
explicit constexpr scope_guard(T&& exit_func, S&& invoke_checker)
208+
noexcept(std::is_nothrow_constructible_v<ScopeExitFunc> && std::is_nothrow_constructible_v<InvokeChecker>)
209+
requires ((!std::is_lvalue_reference_v<T> || !std::is_nothrow_constructible_v<ScopeExitFunc, T>)
210+
&& ( !std::is_lvalue_reference_v<S> || !std::is_nothrow_constructible_v<InvokeChecker, S> ))
211+
try
212+
: m_exit_func(exit_func),
213+
m_invoke_checker{ invoke_checker }
214+
{}
215+
catch (...)
216+
{
217+
if constexpr (!std::is_nothrow_constructible_v<ScopeExitFunc>)
218+
{
219+
if constexpr (!HasDontInvokeOnCreationException<ScopeExitFunc>)
220+
{
221+
exit_func();
222+
}
223+
224+
throw;
225+
}
226+
}
227+
228+
135229
template<typename T>
136230
explicit constexpr scope_guard(T&& exit_func)
137-
// Is the noexcept depending only on scope_exit construct or also on invoke_checker construct?
138-
//noexcept(std::is_nothrow_constructible_v<ScopeExitFunc>)
139231
noexcept(std::is_nothrow_constructible_v<ScopeExitFunc> && std::is_nothrow_constructible_v<InvokeChecker>)
140-
requires (!std::is_same_v<decltype(exit_func), scope_guard>)
232+
requires (!std::is_same_v<std::remove_cvref<T>, scope_guard> && std::is_lvalue_reference_v<T>)
233+
try
234+
: m_exit_func(exit_func)
235+
{}
236+
catch (...)
237+
{
238+
if constexpr (!std::is_nothrow_constructible_v<ScopeExitFunc>)
239+
{
240+
if constexpr (!HasDontInvokeOnCreationException<ScopeExitFunc>)
241+
{
242+
// Can we call the invoke_checker?? we don't know who threw the exception? (exit_func or invoke_checker default construct?)
243+
244+
exit_func();
245+
}
246+
247+
throw;
248+
}
249+
}
250+
251+
template<typename T>
252+
explicit constexpr scope_guard(T&& exit_func)
253+
noexcept(std::is_nothrow_constructible_v<ScopeExitFunc> && std::is_nothrow_constructible_v<InvokeChecker>)
254+
requires (!std::is_same_v<std::remove_cvref<T>, scope_guard> && !std::is_lvalue_reference_v<T>)
141255
try
142256
: m_exit_func(std::forward<T>(exit_func))
143257
{}
@@ -163,8 +277,14 @@ class [[nodiscard]] scope_guard
163277
: m_exit_func { std::move(rhs.m_exit_func) },
164278
m_invoke_checker { std::move(rhs.m_invoke_checker) }
165279
{
166-
rhs.release();
167-
//rhs.m_invoke_checker = NeverExecute {};
280+
if constexpr (HasRelease<InvokeChecker>)
281+
{
282+
rhs.release();
283+
}
284+
else
285+
{
286+
InvokeChecker::release();
287+
}
168288
}
169289

170290

@@ -195,8 +315,8 @@ class [[nodiscard]] scope_guard
195315
}
196316

197317
private:
198-
[[no_unique_address]] ScopeExitFunc m_exit_func;
199-
[[no_unique_address]] InvokeChecker m_invoke_checker;
318+
[[msvc::no_unique_address]] ScopeExitFunc m_exit_func;
319+
[[msvc::no_unique_address]] InvokeChecker m_invoke_checker;
200320

201321
template<typename T>
202322
static constexpr bool check_can_invoke(const T& obj) // noexcept?? how??
@@ -219,10 +339,14 @@ class [[nodiscard]] scope_guard
219339
//==================================================================================================
220340

221341
template<std::invocable ExitFunc, scope_invoke_checker InvokeChecker>
222-
scope_guard(ExitFunc&&, InvokeChecker&&) -> scope_guard<ExitFunc, InvokeChecker>;
342+
scope_guard(ExitFunc, InvokeChecker) -> scope_guard<ExitFunc, InvokeChecker>;
343+
344+
template<std::invocable ExitFunc, typename InvokeChecker>
345+
scope_guard(ExitFunc) -> scope_guard<ExitFunc, InvokeChecker>;
223346

224347
template<std::invocable ExitFunc>
225-
scope_guard(ExitFunc&&) -> scope_guard<ExitFunc>;
348+
scope_guard(ExitFunc) -> scope_guard<ExitFunc>;
349+
226350

227351
//==================================================================================================
228352

0 commit comments

Comments
 (0)