Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
bind_back.hpp
Go to the documentation of this file.
1// parasoft-suppress ALL "False Positive: there is no executable code on line 1"
2// parasoft-begin-suppress AUTOSAR-A2_8_1-a-2 "False positive: also defines arene::base::bind_front"
3
4// Copyright 2026, Toyota Motor Corporation
5//
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7
8#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_FUNCTIONAL_BIND_BACK_HPP_
9#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_FUNCTIONAL_BIND_BACK_HPP_
10
11// IWYU pragma: private, include "arene/base/functional.hpp"
12// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
13
14// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
15#include "arene/base/compiler_support/cpp14_inline.hpp"
16#include "arene/base/functional/invoke.hpp"
17#include "arene/base/functional/perfect_forward_call_wrapper.hpp"
18#include "arene/base/stdlib_choice/cstddef.hpp"
19#include "arene/base/stdlib_choice/decay.hpp"
20#include "arene/base/stdlib_choice/forward.hpp"
21#include "arene/base/stdlib_choice/integer_sequence.hpp"
22#include "arene/base/stdlib_choice/is_constructible.hpp"
23#include "arene/base/stdlib_choice/is_move_constructible.hpp"
24#include "arene/base/stdlib_choice/tuple.hpp"
25#include "arene/base/type_traits/all_of.hpp"
26// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
27
28namespace arene {
29namespace base {
30
31namespace bind_back_detail {
32
33/// @brief Forward declaration to allow specialization
34/// @tparam NBound The number of bound arguments.
35/// @tparam Indexes A @c std::index_sequence of size @c NBound .
36template <std::size_t NBound, typename Indexes = std::make_index_sequence<NBound>>
37class bind_back_policy;
38
39/// @brief Implementation helper for @c arene::base::bind_back intended to be used as a policy for
40/// @c arene::base::functional_detail::perfect_forwarding_call_wrapper .
41///
42/// @tparam NBound The number of bound arguments.
43/// @tparam Is The set of indexes of the bound arguments in the BoundArgs tuple .
44template <std::size_t NBound, std::size_t... Is>
45class bind_back_policy<NBound, std::index_sequence<Is...>> {
46 public:
47 /// @brief Invokes the provided function as expression-equivalent to @c func(call_args...,bound_args...) .
48 ///
49 /// @tparam FuncT The type of the callable to invoke.
50 /// @tparam BoundArgsTupleT The type of a tuple holding the bound arguments.
51 /// @tparam CallArgsT The types of the call arguments to invoke the callable with.
52 /// @param func The invocable to invoke.
53 /// @param bound_args A tuple of bound arguments to pass to the invocable.
54 /// @param call_args The set of call arguments to pass to the invocable.
55 /// @return The return from invoking the held callable with the bound and call arguments.
56 template <typename FuncT, typename BoundArgsTupleT, typename... CallArgsT>
57 constexpr auto operator()(FuncT&& func, BoundArgsTupleT&& bound_args, CallArgsT&&... call_args) const
58 noexcept((noexcept(::arene::base::invoke(
59 std::forward<FuncT>(func),
60 std::forward<CallArgsT>(call_args)...,
61 std::get<Is>(std::forward<BoundArgsTupleT>(bound_args))...
62 ))))
63 -> decltype(::arene::base::invoke(
64 std::forward<FuncT>(func),
65 std::forward<CallArgsT>(call_args)...,
66 std::get<Is>(std::forward<BoundArgsTupleT>(bound_args))...
67 )) {
68 return ::arene::base::invoke(
69 std::forward<FuncT>(func),
70 std::forward<CallArgsT>(call_args)...,
71 std::get<Is>(std::forward<BoundArgsTupleT>(bound_args))...
72 );
73 }
74};
75
76/// @brief Simplifies correctly setting up the call wrapper and policy
77///
78/// @tparam BoundFunc The type of the function to bind, post decaying.
79/// @tparam BoundArgs The type of the arguments to bind, post decaying.
80/// @note This needs to be a struct rather than just a type alias or else gcc crashes on all versions between 8 and 12.
81template <typename BoundFunc, typename... BoundArgs>
82class bind_back_t
83 : functional_detail::perfect_forward_call_wrapper<bind_back_policy<sizeof...(BoundArgs)>, BoundFunc, BoundArgs...> {
84 /// @brief specialization of perfect_forward_call_wrapper that binds arguments to the back
85 using impl_type =
86 functional_detail::perfect_forward_call_wrapper<bind_back_policy<sizeof...(BoundArgs)>, BoundFunc, BoundArgs...>;
87
88 public:
89 using impl_type::impl_type;
90 using impl_type::operator();
91};
92
93/// @brief function object implementing bind_back
94class bind_back_fn {
95 public:
96 /// @brief Produces a call wrapper which allows invoking an input callable with its last N arguments bound to @c args
97 /// .
98 ///
99 /// @tparam BoundFunc The type of the callable to create a wrapper for. Must satisfy
100 // @c std::is_constructible<std::decay_t<BoundFunc>,BoundFunc> and
101 // @c std::is_move_constructible<std::decay_t<BoundFunc>> or else the program is ill-formed.
102 /// @tparam BoundArgs The types of the arguments to bind to the callable. Must satisfy
103 // @c std::is_constructible<std::tuple<std::decay_t<BoundArgs>...>, BoundArgs&&...> and
104 // @c std::is_move_constructible<std::tuple<std::decay_t<BoundArgs>...>> or else the program is ill-formed.
105 /// @param bound_func The callable to create a wrapper for. It will be perfect-forwarded into the call wrapper.
106 /// @param bound_args The set of arguments to bind to the callable. They will be perfect-forwarded into the call
107 /// wrapper.
108 /// @return An implementation defined callable object, whose call operator can consume a set of arguments @c call_args
109 /// .
110 /// <c> bind_back(bound_func, bound_args...)(call_args...) </c> is expression-equivalent to
111 /// <c> invoke(bound_func, call_args..., bound_args...) </c> . The @c noexcept -ness of @c bound_func is
112 /// preserved by the call operator of the returned object.
113 ///
114 /// The wrapper perfect forwards the input callable and binding arguments _into the wrapper_, otherwise temporaries
115 /// would always dangle, and references would be at high risk of dangling. When the returned callable is invoked, its
116 /// reference qualification is applied to the access of the bound objects. If @c g is the callable returned from @c
117 /// bind_front(f,args...) , then invoking @c std::move(g)(call_args...) will allow the bound arguments to be moved
118 /// into the bound callable. Similarly, if @c f were to have non-const lvalue parameters at the position of bound
119 /// arguments, then invoking @c g(call_args..) when @c g is a non-const lvalue will result in the instances of the
120 /// bound arguments held in the wrapper being passed to @c f , similar to a @c mutable lambda with a capture block.
121 ///
122 /// If a caller wishes to maintain "reference semantics" of the bound arguments when it can be assured the lifetime of
123 /// the bound arguments will exceed the lifetime of the returned callable, this can be achieved by wrapping the
124 /// argument in @c std::reference_wrapper .
125 // parasoft-begin-suppress CERT_C-EXP37-a "False positive: there is no function pointer decay/conversion."
126 // parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: static cannot be applied, this is not a member function."
127 template <typename BoundFunc, typename... BoundArgs>
128 constexpr auto operator()(BoundFunc&& bound_func, BoundArgs&&... bound_args) const noexcept(
129 std::is_nothrow_constructible<std::decay_t<BoundFunc>, BoundFunc>::value &&
130 std::is_nothrow_constructible<std::tuple<std::decay_t<BoundArgs>...>, BoundArgs&&...>::value
131 ) -> bind_back_detail::bind_back_t<std::decay_t<BoundFunc>, std::decay_t<BoundArgs>...> {
132 static_assert(
133 std::is_constructible<std::decay_t<BoundFunc>, BoundFunc&&>::value,
134 "Bound function must be constructible from input."
135 );
136 static_assert(
137 std::is_move_constructible<std::decay_t<BoundFunc>>::value,
138 "Bound function must be move-constructible."
139 );
140 static_assert(
141 ::arene::base::all_of_v<std::is_constructible<std::decay_t<BoundArgs>, BoundArgs&&>::value...>,
142 "Bound arguments must be capturable from input."
143 );
144 static_assert(
145 ::arene::base::all_of_v<std::is_move_constructible<std::decay_t<BoundArgs>>::value...>,
146 "Bound arguments must be move-constructible."
147 );
148 return bind_back_detail::bind_back_t<std::decay_t<BoundFunc>, std::decay_t<BoundArgs>...>{
149 std::forward<BoundFunc>(bound_func),
150 std::forward<BoundArgs>(bound_args)...,
151 };
152 }
153 // parasoft-end-suppress AUTOSAR-M3_3_2-a "False positive: static cannot be applied, this is not a member function."
154 // parasoft-begin-suppress CERT_C-EXP37-a "False positive: there is no function pointer decay/conversion."
155};
156
157} // namespace bind_back_detail
158
159/// @def arene::base::bind_back
160/// @copydoc arene::base::bind_back_detail::bind_back_fn::operator()
161// parasoft-begin-suppress AUTOSAR-M7_3_3-a "An unnamed namespace is used to create a per-TU reference to a global
162// object used in multiple TUs."
163// parasoft-begin-suppress CERT_CPP-DCL59-a "An unnamed namespace is used to create a per-TU reference to a global
164// object used in multiple TUs."
165ARENE_CPP14_INLINE_VARIABLE(bind_back_detail::bind_back_fn, bind_back);
166// parasoft-end-suppress AUTOSAR-M7_3_3-a
167// parasoft-end-suppress CERT_CPP-DCL59-a
168
169} // namespace base
170} // namespace arene
171
172// parasoft-end-suppress AUTOSAR-A2_8_1-a-2
173
174#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_FUNCTIONAL_BIND_BACK_HPP_
Definition array_exceptions_disabled.cpp:11
ARENE_CPP14_INLINE_VARIABLE(bind_back_detail::bind_back_fn, bind_back)
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10