@@ -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+
110119template <scope_exit_function ScopeExitFunc, scope_invoke_checker InvokeChecker = ExecuteAlways>
111120class [[nodiscard]] scope_guard
112121{
113122public:
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
197317private:
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
221341template <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
224347template <std::invocable ExitFunc>
225- scope_guard (ExitFunc&&) -> scope_guard<ExitFunc>;
348+ scope_guard (ExitFunc) -> scope_guard<ExitFunc>;
349+
226350
227351// ==================================================================================================
228352
0 commit comments