Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
perfect_forward_call_wrapper.hpp
Go to the documentation of this file.
1// parasoft-suppress ALL "False Positive: there is no executable code on line 1"
2
3// Copyright 2026, Toyota Motor Corporation
4//
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
7#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_FUNCTIONAL_PERFECT_FORWARD_CALL_WRAPPER_HPP_
8#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_FUNCTIONAL_PERFECT_FORWARD_CALL_WRAPPER_HPP_
9
10// IWYU pragma: private, include "arene/base/functional.hpp"
11// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
12
13// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
14#include "arene/base/constraints/constraints.hpp"
15#include "arene/base/stdlib_choice/enable_if.hpp"
16#include "arene/base/stdlib_choice/forward.hpp"
17#include "arene/base/stdlib_choice/is_constructible.hpp"
18#include "arene/base/stdlib_choice/move.hpp"
19#include "arene/base/stdlib_choice/tuple.hpp"
20#include "arene/base/type_manipulation/ebo_holder.hpp"
21#include "arene/base/type_traits/decays_to.hpp"
22#include "arene/base/type_traits/give_cvref_to.hpp"
23#include "arene/base/type_traits/is_invocable.hpp"
24// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
25
26// parasoft-begin-suppress AUTOSAR-M2_10_1-a "Similar identifiers permitted by M2-10-1 Permit #1 v1.0.0"
27
28namespace arene {
29namespace base {
30
31namespace functional_detail {
32
33/// @brief A tag type to allow empty base class optimization for empty function objects.
34template <class Self>
35struct invoke_tag {};
36
37/// @brief A tag type to allow empty base class optimization for empty bound arguments.
38template <class Self>
39struct bound_args_tag {};
40
41// parasoft-begin-suppress AUTOSAR-A10_2_1-b "'perfect_forward_call_wrapper::invocable' and
42// 'perfect_forward_call_Wrapper::bound_args' are not part of the public interface and are not hidden."
43
44/// @brief A Perfect Forwarding Call Wrapper which holds a functor and bound arguments and dispatches to a policy.
45///
46/// The primary utility of this wrapper is the following:
47///
48// #. Store the functor
49/// #. Store the bound arguments
50/// #. Handle "perfect forwarding" of the functor and bound arguments to the bound policy. This means not only ensuring
51/// the cref qualification of the object is properly propagated to the callable and arguments, but critically it also
52/// means ensuring that if @c BoundFuncT declares a given call operator overload as @c =delete; , then the equivalent
53/// operator overload is also deleted in the wrapper. See [this
54/// article](https://quuxplusone.github.io/blog/2021/07/30/perfect-forwarding-call-wrapper/) for additional details.
55/// @c noexcept of the given overload is also propagated.
56///
57/// The @c Policy is an _invocable_ which the actual work of invoking the function with the bound arguments and call
58/// arguments. It will be invoked as <c>Policy{}(func, bound_args, call_args...)</c> where @c func is the instance of @c
59/// BoundFuncT and @c bound_args is @c std::tuple<BoundArgs...> , both with the appropriate cref qualification.
60/// @c call_args... are the forwarded arguments to the invoked call operator.
61///
62/// @see arene::base::bind_front for an example usage.
63///
64/// @tparam Policy An invocable policy to use which actually invokes the function with arguments.
65/// @tparam Func The type of the function object to bind.
66/// @tparam BoundArgs The types of the bound arguments.
67///
68// parasoft-begin-suppress AUTOSAR-A12_1_5-a "False positive: There are no constructors to delegate to."
69// parasoft-begin-suppress AUTOSAR-A10_1_1-a "Multiple base classes needed for empty-base-class optimizations."
70template <typename Policy, typename Func, typename... BoundArgs>
71class perfect_forward_call_wrapper
72 : ebo_holder<invoke_tag<perfect_forward_call_wrapper<Policy, Func, BoundArgs...>>, Func>
73 , ebo_holder<bound_args_tag<perfect_forward_call_wrapper<Policy, Func, BoundArgs...>>, std::tuple<BoundArgs...>> {
74 /// @brief The type of a tuple containing any bound arguments
75 using bound_arg_tuple = std::tuple<BoundArgs...>;
76
77 /// @brief The type of the ebo holder for the function object
78 using invocable_wrapper = ebo_holder<invoke_tag<perfect_forward_call_wrapper>, Func>;
79
80 /// @brief The type of the ebo holder for the bound arguments
81 using bound_args_wrapper = ebo_holder<bound_args_tag<perfect_forward_call_wrapper>, bound_arg_tuple>;
82
83 // parasoft-begin-suppress AUTOSAR-A8_4_6-a "False positive: 'self' is forwarded correctly by use of 'static_cast'"
84 // parasoft-begin-suppress AUTOSAR-A8_4_5-a "False positive: 'self' is forwarded correctly by use of 'static_cast'"
85 // parasoft-begin-suppress AUTOSAR-A12_8_4-a "False positive: 'self' is forwarded correctly by use of 'static_cast'"
86
87 /// @brief access the stored invocable with the cvref-qualification of the wrapper
88 /// @tparam Self type of the wrapper
89 /// @param self reference to a wrapper
90 /// @return reference to the stored invocable, cvref-qualified to match @c Self
91 template <class Self>
92 static constexpr auto invocable(Self&& self) noexcept -> give_cvref_to_t<Self&&, Func> {
93 return static_cast<give_cvref_to_t<Self&&, invocable_wrapper>>(self).get_value(
94 invoke_tag<perfect_forward_call_wrapper>{}
95 );
96 }
97
98 /// @brief access the stored args with the cvref-qualification of the wrapper
99 /// @tparam Self type of the wrapper
100 /// @param self reference to a wrapper
101 /// @return reference to the stored argument tuple, cvref-qualified to match @c Self
102 template <class Self>
103 static constexpr auto bound_args(Self&& self) noexcept -> give_cvref_to_t<Self&&, std::tuple<BoundArgs...>> {
104 return static_cast<give_cvref_to_t<Self&&, bound_args_wrapper>>(self).get_value(
105 bound_args_tag<perfect_forward_call_wrapper>{}
106 );
107 }
108
109 // parasoft-end-suppress AUTOSAR-A8_4_6-a
110 // parasoft-end-suppress AUTOSAR-A8_4_5-a
111 // parasoft-end-suppress AUTOSAR-A12_8_4-a
112
113 protected:
114 /// @brief default copy ctor
115 constexpr perfect_forward_call_wrapper(perfect_forward_call_wrapper const& copy) = default;
116 /// @brief default move ctor
117 constexpr perfect_forward_call_wrapper(perfect_forward_call_wrapper&& move) = default;
118 /// @brief default copy-assignment
119 constexpr auto operator=(perfect_forward_call_wrapper const& copy) -> perfect_forward_call_wrapper& = default;
120 /// @brief default move-assignment
121 constexpr auto operator=(perfect_forward_call_wrapper&& move) -> perfect_forward_call_wrapper& = default;
122
123 public:
124 /// @brief Constructs the argument binding wrapper with the given function and bound arguments
125 ///
126 /// @tparam BoundFunc The type of the function object to bind.
127 /// @tparam ArgsToBind The types of the bound arguments.
128 /// @param func_to_bind The function to bind
129 /// @param args_to_bind The arguments to bind
130 template <
131 typename BoundFunc,
132 typename... ArgsToBind,
133 constraints<
134 std::enable_if_t<!decays_to_v<BoundFunc, perfect_forward_call_wrapper>>,
135 std::enable_if_t<std::is_constructible<Func, BoundFunc&&>::value>,
136 std::enable_if_t<std::is_constructible<std::tuple<BoundArgs...>, ArgsToBind&&...>::value>> = nullptr>
137 constexpr explicit perfect_forward_call_wrapper(BoundFunc&& func_to_bind, ArgsToBind&&... args_to_bind) noexcept(
138 std::is_nothrow_constructible<Func, BoundFunc&&>::value &&
139 std::is_nothrow_constructible<std::tuple<BoundArgs...>, ArgsToBind&&...>::value
140 )
141 : invocable_wrapper{std::forward<BoundFunc>(func_to_bind)},
142 bound_args_wrapper{std::forward<ArgsToBind>(args_to_bind)...} {
143 static_assert(sizeof...(ArgsToBind) == sizeof...(BoundArgs), "Must store all bound arguments");
144 }
145
146 /// @brief default dtor
147 ~perfect_forward_call_wrapper() = default;
148
149 /// @brief Invokes the held callable with both the held bound arguments and the call arguments.
150 ///
151 /// @tparam CallArgsT The types of the call arguments to invoke the callable with.
152 /// @param call_args The set of call arguments to invoke the callable with.
153 /// @return The return from invoking the held callable with the bound and call arguments.
154 template <
155 typename... CallArgsT,
156 constraints<std::enable_if_t<is_invocable_v<Policy, Func&, bound_arg_tuple&, CallArgsT&&...>>> = nullptr>
157 constexpr auto operator()(CallArgsT&&... call_args) & noexcept( //
158 is_nothrow_invocable_v<Policy, Func&, bound_arg_tuple&, CallArgsT&&...> //
159 ) -> invoke_result_t<Policy, Func&, bound_arg_tuple&, CallArgsT&&...> {
160 // parasoft-begin-suppress AUTOSAR-M14_6_1-a "False positive: The dependent name is qualified."
161 return Policy{}( //
162 invocable(*this),
163 bound_args(*this),
164 std::forward<CallArgsT>(call_args)...
165 );
166 // parasoft-end-suppress AUTOSAR-M14_6_1-a "False positive: The dependent name is qualified."
167 }
168
169 /// @brief Deleted lvalue overload if the wrapped callable's operator() is explicitly deleted for lvalues.
170 ///
171 /// @tparam CallArgsT The types of the call arguments to invoke the callable with.
172 /// @param call_args The set of call arguments to invoke the callable with.
173 // parasoft-begin-suppress CERT_C-EXP37-a "False positive: this operator is deleted, it invokes nothing."
174 template <
175 typename... CallArgsT,
176 constraints<std::enable_if_t<!is_invocable_v<Policy, Func&, bound_arg_tuple&, CallArgsT&&...>>> = nullptr>
177 constexpr auto operator()(CallArgsT&&... call_args) & = delete;
178 // parasoft-end-suppress CERT_C-EXP37-a
179
180 /// @brief Invokes the held callable with both the held bound arguments and the call arguments.
181 ///
182 /// @tparam CallArgsT The types of the call arguments to invoke the callable with.
183 /// @param call_args The set of call arguments to invoke the callable with.
184 /// @return The return from invoking the held callable with the bound and call arguments.
185 template <
186 typename... CallArgsT,
187 constraints<std::enable_if_t<is_invocable_v<Policy, Func const&, bound_arg_tuple const&, CallArgsT&&...>>> =
188 nullptr>
189 constexpr auto operator()(CallArgsT&&... call_args) const& noexcept( //
190 is_nothrow_invocable_v<Policy, Func const&, bound_arg_tuple const&, CallArgsT&&...> //
191 ) -> invoke_result_t<Policy, Func const&, bound_arg_tuple const&, CallArgsT&&...> {
192 // parasoft-begin-suppress AUTOSAR-M14_6_1-a "False positive: The dependent name is qualified."
193 return Policy{}( //
194 invocable(*this),
195 bound_args(*this),
196 std::forward<CallArgsT>(call_args)...
197 );
198 // parasoft-end-suppress AUTOSAR-M14_6_1-a "False positive: The dependent name is qualified."
199 }
200
201 /// @brief Deleted const lvalue overload if the wrapped callable's operator() is explicitly deleted for const lvalues.
202 ///
203 /// @tparam CallArgsT The types of the call arguments to invoke the callable with.
204 /// @param call_args The set of call arguments to invoke the callable with.
205 // parasoft-begin-suppress CERT_C-EXP37-a "False positive: this operator is deleted, it invokes nothing."
206 template <
207 typename... CallArgsT,
208 constraints<std::enable_if_t<!is_invocable_v<Policy, Func const&, bound_arg_tuple const&, CallArgsT&&...>>> =
209 nullptr>
210 constexpr auto operator()(CallArgsT&&... call_args) const& = delete;
211 // parasoft-end-suppress CERT_C-EXP37-a
212
213 /// @brief Invokes the held callable with both the held bound arguments and the call arguments.
214 ///
215 /// @tparam CallArgsT The types of the call arguments to invoke the callable with.
216 /// @param call_args The set of call arguments to invoke the callable with.
217 /// @return The return from invoking the held callable with the bound and call arguments.
218 template <
219 typename... CallArgsT,
220 constraints<std::enable_if_t<is_invocable_v<Policy, Func&&, bound_arg_tuple&&, CallArgsT&&...>>> = nullptr>
221 constexpr auto operator()(CallArgsT&&... call_args) && noexcept( //
222 is_nothrow_invocable_v<Policy, Func&&, bound_arg_tuple&&, CallArgsT&&...> //
223 ) -> invoke_result_t<Policy, Func&&, bound_arg_tuple&&, CallArgsT&&...> {
224 // parasoft-begin-suppress AUTOSAR-M14_6_1-a "False positive: The dependent name is qualified."
225 return Policy{}( //
226 invocable(std::move(*this)),
227 bound_args(std::move(*this)),
228 std::forward<CallArgsT>(call_args)...
229 );
230 // parasoft-end-suppress AUTOSAR-M14_6_1-a "False positive: The dependent name is qualified."
231 }
232
233 /// @brief Deleted lvalue overload if the wrapped callable's operator() is explicitly deleted for rvalues.
234 ///
235 /// @tparam CallArgsT The types of the call arguments to invoke the callable with.
236 /// @param call_args The set of call arguments to invoke the callable with.
237 // parasoft-begin-suppress CERT_C-EXP37-a "False positive: this operator is deleted, it invokes nothing."
238 template <
239 typename... CallArgsT,
240 constraints<std::enable_if_t<!is_invocable_v<Policy, Func&&, bound_arg_tuple&&, CallArgsT&&...>>> = nullptr>
241 constexpr auto operator()(CallArgsT&&... call_args) && = delete;
242 // parasoft-end-suppress CERT_C-EXP37-a
243
244 /// @brief Invokes the held callable with both the held bound arguments and the call arguments.
245 ///
246 /// @tparam CallArgsT The types of the call arguments to invoke the callable with.
247 /// @param call_args The set of call arguments to invoke the callable with.
248 /// @return The return from invoking the held callable with the bound and call arguments.
249 template <
250 typename... CallArgsT,
251 constraints<std::enable_if_t<is_invocable_v<Policy, Func const&&, bound_arg_tuple const&&, CallArgsT&&...>>> =
252 nullptr>
253 constexpr auto operator()(CallArgsT&&... call_args) const&& noexcept( //
254 is_nothrow_invocable_v<Policy, Func const&&, bound_arg_tuple const&&, CallArgsT&&...> //
255 ) -> invoke_result_t<Policy, Func const&&, bound_arg_tuple const&&, CallArgsT&&...> {
256 // parasoft-begin-suppress AUTOSAR-M14_6_1-a "False positive: The dependent name is qualified."
257 // parasoft-begin-suppress AUTOSAR-A18_9_3-a "const-rvalue overload, so arguments must still be moved."
258 return Policy{}( //
259 invocable(std::move(*this)),
260 bound_args(std::move(*this)),
261 std::forward<CallArgsT>(call_args)...
262 );
263 // parasoft-end-suppress AUTOSAR-A18_9_3-a "const-rvalue overload, so arguments must still be moved."
264 // parasoft-end-suppress AUTOSAR-M14_6_1-a "False positive: The dependent name is qualified."
265 }
266
267 /// @brief Deleted const rvalue overload if the wrapped callable's operator() is explicitly deleted for const rvalues.
268 ///
269 /// @tparam CallArgsT The types of the call arguments to invoke the callable with.
270 /// @param call_args The set of call arguments to invoke the callable with.
271 // parasoft-begin-suppress CERT_C-EXP37-a "False positive: this operator is deleted, it invokes nothing."
272 template <
273 typename... CallArgsT,
274 constraints<std::enable_if_t<!is_invocable_v<Policy, Func const&&, bound_arg_tuple const&&, CallArgsT&&...>>> =
275 nullptr>
276 constexpr auto operator()(CallArgsT&&... call_args) const&& = delete;
277 // parasoft-end-suppress CERT_C-EXP37-a
278};
279// parasoft-end-suppress AUTOSAR-A10_1_1-a "Multiple base classes needed for empty-base-class optimizations."
280// parasoft-end-suppress AUTOSAR-A12_1_5-a
281
282// parasoft-end-suppress AUTOSAR-A10_2_1-b
283
284} // namespace functional_detail
285
286} // namespace base
287} // namespace arene
288
289#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_FUNCTIONAL_PERFECT_FORWARD_CALL_WRAPPER_HPP_
290
291// parasoft-end-suppress CERT_C-EXP37-a "False positive: The rule does not mention naming all parameters"
292// parasoft-end-suppress AUTOSAR-A5_0_3-a "False positive: There is no pointer indirection in return types"
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10