@@ -61,6 +61,37 @@ template <auto V> struct tombstone_value {
6161 }
6262};
6363
64+ namespace optional_detail {
65+ template <typename Func, typename Arg, typename = void > struct unwrap_invoker {
66+ template <typename F, typename A>
67+ constexpr static auto invoke (F &&f, A &&a) {
68+ return [&] { return std::forward<F>(f)(std::forward<A>(a)); };
69+ }
70+ };
71+
72+ template <typename Func, template <typename ...> typename L, typename ... Ts>
73+ struct unwrap_invoker <Func, L<Ts...>,
74+ std::void_t <decltype (apply(std::declval<Func>(),
75+ std::declval<L<Ts...>>()))>> {
76+ template <typename F, typename A>
77+ constexpr static auto invoke (F &&f, A &&a) {
78+ return [&] { return apply (std::forward<F>(f), std::forward<A>(a)); };
79+ }
80+ };
81+
82+ template <typename F, typename Arg>
83+ constexpr auto unwrap_invoke (F &&f, Arg &&arg) {
84+ return unwrap_invoker<stdx::remove_cvref_t <F>,
85+ stdx::remove_cvref_t <Arg>>::invoke (std::forward<F>(f),
86+ std::forward<Arg>(
87+ arg));
88+ }
89+
90+ template <typename F, typename Arg>
91+ using unwrap_invoke_result_t =
92+ decltype (unwrap_invoke(std::declval<F>(), std::declval<Arg>())());
93+ } // namespace optional_detail
94+
6495template <typename T, typename TS = tombstone_traits<T>> class optional {
6596 static_assert (not std::is_integral_v<T> or
6697 not stdx::is_specialization_of_v<TS, tombstone_traits>,
@@ -169,32 +200,34 @@ template <typename T, typename TS = tombstone_traits<T>> class optional {
169200 }
170201
171202 template <typename F> constexpr auto transform (F &&f) & {
172- using func_t = stdx:: remove_cvref_t <F >;
173- using U = std:: invoke_result_t < func_t , value_type &>;
174- return * this ? optional<U>{with_result_of{
175- [&] { return std::forward<F>(f)( val); } }}
176- : optional<U>{};
203+ using U = optional_detail:: unwrap_invoke_result_t <F, value_type & >;
204+ return * this
205+ ? optional<U>{with_result_of{optional_detail::unwrap_invoke (
206+ std::forward<F>(f), val)}}
207+ : optional<U>{};
177208 }
178209 template <typename F> constexpr auto transform (F &&f) const & {
179- using func_t = stdx::remove_cvref_t <F>;
180- using U = std::invoke_result_t <func_t , value_type const &>;
181- return *this ? optional<U>{with_result_of{
182- [&] { return std::forward<F>(f)(val); }}}
183- : optional<U>{};
210+ using U =
211+ optional_detail::unwrap_invoke_result_t <F, value_type const &>;
212+ return *this
213+ ? optional<U>{with_result_of{optional_detail::unwrap_invoke (
214+ std::forward<F>(f), val)}}
215+ : optional<U>{};
184216 }
185217 template <typename F> constexpr auto transform (F &&f) && {
186- using func_t = stdx:: remove_cvref_t <F >;
187- using U = std:: invoke_result_t < func_t , value_type &&>;
188- return * this ? optional<U>{with_result_of{
189- [&] { return std::forward<F>(f)( std::move (val)); } }}
190- : optional<U>{};
218+ using U = optional_detail:: unwrap_invoke_result_t <F, value_type && >;
219+ return * this
220+ ? optional<U>{with_result_of{optional_detail::unwrap_invoke (
221+ std::forward<F>(f), std::move (val))}}
222+ : optional<U>{};
191223 }
192224 template <typename F> constexpr auto transform (F &&f) const && {
193- using func_t = stdx::remove_cvref_t <F>;
194- using U = std::invoke_result_t <func_t , value_type const &&>;
195- return *this ? optional<U>{with_result_of{
196- [&] { return std::forward<F>(f)(std::move (val)); }}}
197- : optional<U>{};
225+ using U =
226+ optional_detail::unwrap_invoke_result_t <F, value_type const &&>;
227+ return *this
228+ ? optional<U>{with_result_of{optional_detail::unwrap_invoke (
229+ std::forward<F>(f), std::move (val))}}
230+ : optional<U>{};
198231 }
199232
200233 template <typename F> constexpr auto or_else (F &&f) const & -> optional {
@@ -205,24 +238,28 @@ template <typename T, typename TS = tombstone_traits<T>> class optional {
205238 }
206239
207240 template <typename F> constexpr auto and_then (F &&f) & {
208- using func_t = stdx:: remove_cvref_t <F >;
209- using U = std::invoke_result_t < func_t , value_type &>;
210- return * this ? std::forward<F>(f)(val) : U{};
241+ using U = optional_detail:: unwrap_invoke_result_t <F, value_type & >;
242+ return * this ? optional_detail::unwrap_invoke ( std::forward<F>(f), val)()
243+ : U{};
211244 }
212245 template <typename F> constexpr auto and_then (F &&f) const & {
213- using func_t = stdx::remove_cvref_t <F>;
214- using U = std::invoke_result_t <func_t , value_type const &>;
215- return *this ? std::forward<F>(f)(val) : U{};
246+ using U =
247+ optional_detail::unwrap_invoke_result_t <F, value_type const &>;
248+ return *this ? optional_detail::unwrap_invoke (std::forward<F>(f), val)()
249+ : U{};
216250 }
217251 template <typename F> constexpr auto and_then (F &&f) && {
218- using func_t = stdx::remove_cvref_t <F>;
219- using U = std::invoke_result_t <func_t , value_type &&>;
220- return *this ? std::forward<F>(f)(std::move (val)) : U{};
252+ using U = optional_detail::unwrap_invoke_result_t <F, value_type &&>;
253+ return *this ? optional_detail::unwrap_invoke (std::forward<F>(f),
254+ std::move (val))()
255+ : U{};
221256 }
222257 template <typename F> constexpr auto and_then (F &&f) const && {
223- using func_t = stdx::remove_cvref_t <F>;
224- using U = std::invoke_result_t <func_t , value_type &&>;
225- return *this ? std::forward<F>(f)(std::move (val)) : U{};
258+ using U =
259+ optional_detail::unwrap_invoke_result_t <F, value_type const &&>;
260+ return *this ? optional_detail::unwrap_invoke (std::forward<F>(f),
261+ std::move (val))()
262+ : U{};
226263 }
227264
228265 private:
@@ -260,6 +297,23 @@ template <typename T, typename TS = tombstone_traits<T>> class optional {
260297 -> bool {
261298 return not (lhs < rhs);
262299 }
300+
301+ template <typename F>
302+ [[nodiscard]] friend constexpr auto operator |(optional const &lhs, F &&f) {
303+ return lhs.and_then (std::forward<F>(f));
304+ }
305+ template <typename F>
306+ [[nodiscard]] friend constexpr auto operator |(optional &lhs, F &&f) {
307+ return lhs.and_then (std::forward<F>(f));
308+ }
309+ template <typename F>
310+ [[nodiscard]] friend constexpr auto operator |(optional &&lhs, F &&f) {
311+ return std::move (lhs).and_then (std::forward<F>(f));
312+ }
313+ template <typename F>
314+ [[nodiscard]] friend constexpr auto operator |(optional const &&lhs, F &&f) {
315+ return std::move (lhs).and_then (std::forward<F>(f));
316+ }
263317};
264318
265319template <typename T> optional (T) -> optional<T>;
0 commit comments