"ScL Feature"/
ScL Feature 0.0.1
C++20 composable proxy wrapper with pluggable executor strategy
Loading...
Searching...
No Matches
operator.h
Go to the documentation of this file.
1#pragma once
2
26
31#include <scl/feature/type_traits/wrapper.h>
32#include <scl/feature/wrapper_cast.h>
33#include <scl/utility/preprocessor/forward.h>
34
35#include <type_traits>
36#include <utility>
37
38// clang-format off
39
60#define SCL_REFLECT_OPERATOR_EXEC_HELPERS(name) \
61 template <typename ScLExec, typename... ScLArgs> \
62 static constexpr bool operator_##name##_scl_has_exec_override = \
63 requires { \
64 static_cast< \
65 decltype(::std::remove_cvref_t<ScLExec>::operator_##name( \
66 ::std::declval<ScLExec>(), ::std::declval<ScLArgs>()...)) \
67 (*)(ScLExec, ScLArgs...) \
68 >(&::std::remove_cvref_t<ScLExec>::operator_##name); \
69 }; \
70 template <typename ScLExec, typename... ScLArgs> \
71 static constexpr bool operator_##name##_scl_exec_noexcept = \
72 []() constexpr noexcept -> bool { \
73 if constexpr (operator_##name##_scl_has_exec_override<ScLExec, ScLArgs...>) \
74 return noexcept(::std::remove_cvref_t<ScLExec>::operator_##name( \
75 ::std::declval<ScLExec>(), ::std::declval<ScLArgs>()...)); \
76 return false; \
77 }();
78
92#define SCL_REFLECT_OPERATOR_CALLER(op, name) \
93 struct operator_##name##_scl_caller \
94 { \
95 template <typename ScLParam, typename... ScLParams, \
96 typename ScLObj, typename... ScLArgs> \
97 static constexpr auto call(ScLObj && scl_obj, ScLArgs &&... scl_args) \
98 -> decltype(::std::forward<ScLObj>(scl_obj) \
99 .template operator op/**/<ScLParam, ScLParams...>( \
100 ::scl::wrapper_cast(::std::forward<ScLArgs>(scl_args))...)) \
101 { \
102 return ::std::forward<ScLObj>(scl_obj) \
103 .template operator op/**/<ScLParam, ScLParams...>( \
104 ::scl::wrapper_cast(::std::forward<ScLArgs>(scl_args))...); \
105 } \
106 };
107
124#define SCL_REFLECT_OPERATOR_QUALS(op, name) \
125 template <typename ScLVal, typename... ScLArgs> \
126 static constexpr bool operator_##name##_scl_quals = \
127 SCL_HAS_QUALIFIED_METHOD(SCL_FORWARD(operator op), ScLVal, ScLArgs...); \
128 template <typename ScLParam, typename... ScLParams> \
129 struct operator_##name##_scl_template_quals \
130 { \
131 template <typename ScLVal, typename... ScLArgs> \
132 static constexpr bool value = \
133 SCL_HAS_QUALIFIED_METHOD( \
134 SCL_FORWARD(template operator op/**/<ScLParam, ScLParams...>), \
135 ScLVal, ScLArgs...); \
136 };
137
150#define SCL_REFLECT_OPERATOR_EXECUTOR_OVERRIDE_BASE(op, name, cv_ref) \
151 template <typename ScLExec = s_c_l_executor_type cv_ref, typename... ScLArgs> \
152 constexpr decltype(auto) operator op(ScLArgs &&... scl_args) cv_ref \
153 noexcept(operator_##name##_scl_exec_noexcept<ScLExec, ScLArgs...>) \
154 requires \
155 (::std::is_same_v<ScLExec, s_c_l_executor_type cv_ref> \
156 && operator_##name##_scl_has_exec_override<ScLExec, ScLArgs...>) \
157 { \
158 return ::std::remove_cvref_t<ScLExec>::operator_##name( \
159 SCL_EXECUTOR_ACCESS(cv_ref), \
160 ::std::forward<ScLArgs>(scl_args)...); \
161 }
162
173#define SCL_REFLECT_OPERATOR_BASE(op, name, cv_ref) \
174 noexcept (noexcept(SCL_EXECUTE_OVERRIDED(SCL_FORWARD(operator op), cv_ref))) \
175 requires \
176 (!operator_##name##_scl_has_exec_override<s_c_l_executor_type cv_ref, \
177 ScLArgs...> && \
178 requires \
179 { \
180 SCL_ACCESS_DECLVAL(cv_ref).operator op( \
181 ::scl::wrapper_cast(::std::declval<ScLArgs>())...); \
182 } && operator_##name##_scl_quals<decltype(SCL_ACCESS_DECLVAL(cv_ref)), \
183 decltype(::scl::wrapper_cast(::std::declval<ScLArgs>()))...>) \
184 { \
185 return SCL_EXECUTE_OVERRIDED(SCL_FORWARD(operator op), cv_ref); \
186 }
187
199#define SCL_REFLECT_TEMPLATE_OPERATOR_BASE(name, caller, cv_ref) \
200 noexcept(noexcept(SCL_EXECUTE_TEMPLATE_OVERRIDED(caller, cv_ref))) \
201 requires \
202 requires \
203 { \
204 caller::template call<ScLParam, ScLParams...>( \
205 SCL_ACCESS_DECLVAL(cv_ref), ::std::declval<ScLArgs>()...); \
206 } && operator_##name##_scl_template_quals<ScLParam, ScLParams...> \
207 ::template value<decltype(SCL_ACCESS_DECLVAL(cv_ref)), \
208 decltype(::scl::wrapper_cast(::std::declval<ScLArgs>()))...> \
209 { \
210 return SCL_EXECUTE_TEMPLATE_OVERRIDED(caller, cv_ref); \
211 }
212
222#define SCL_REFLECT_OPERATOR_HELPER(op, name, caller, cv_ref) \
223 SCL_REFLECT_OPERATOR_EXECUTOR_OVERRIDE_BASE(SCL_FORWARD(op), name, cv_ref) \
224 template <typename... ScLArgs> \
225 constexpr decltype(auto) operator op(ScLArgs &&... scl_args) cv_ref \
226 SCL_REFLECT_OPERATOR_BASE(SCL_FORWARD(op), name, cv_ref) \
227 template <typename ScLParam, typename... ScLParams, typename... ScLArgs> \
228 constexpr decltype(auto) operator op(ScLArgs &&... scl_args) cv_ref \
229 SCL_REFLECT_TEMPLATE_OPERATOR_BASE(name, caller, cv_ref)
230
237#define SCL_REFLECT_OPERATOR_IMPL(op, name) \
238 SCL_REFLECT_OPERATOR_QUALS(SCL_FORWARD(op), name) \
239 SCL_REFLECT_OPERATOR_CALLER(SCL_FORWARD(op), name) \
240 SCL_REFLECT_OPERATOR_EXEC_HELPERS(name) \
241 SCL_REFLECT_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, &) \
242 SCL_REFLECT_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, &&) \
243 SCL_REFLECT_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, const &) \
244 SCL_REFLECT_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, const &&) \
245 SCL_REFLECT_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, volatile &) \
246 SCL_REFLECT_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, volatile &&) \
247 SCL_REFLECT_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, const volatile &) \
248 SCL_REFLECT_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, const volatile &&)
249
262#define SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(op, name, cv_ref) \
263 template <typename ScLExec = s_c_l_executor_type cv_ref> \
264 constexpr decltype(auto) operator op() cv_ref \
265 noexcept(operator_##name##_scl_exec_noexcept<ScLExec>) \
266 requires \
267 (::std::is_same_v<ScLExec, s_c_l_executor_type cv_ref> \
268 && (operator_##name##_scl_has_exec_override<ScLExec> \
269 || operator_##name##_scl_quals<decltype(SCL_ACCESS_DECLVAL(cv_ref))>)) \
270 { \
271 if constexpr (operator_##name##_scl_has_exec_override<ScLExec>) \
272 { \
273 return ::std::remove_cvref_t<ScLExec>::operator_##name( \
274 SCL_EXECUTOR_ACCESS(cv_ref)); \
275 } \
276 else \
277 { \
278 return ::std::remove_cvref_t<ScLExec>::execute(SCL_EXECUTOR_ACCESS(cv_ref), \
279 [](auto && scl_e) -> decltype(auto) { \
280 return ::std::remove_cvref_t<ScLExec>::access(::std::forward<decltype(scl_e)>(scl_e)) \
281 .operator op(); \
282 }, SCL_EXECUTOR_ACCESS(cv_ref)); \
283 } \
284 }
285
297#define SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(op, name, cv_ref) \
298 template <typename ScLExec = s_c_l_executor_type cv_ref> \
299 constexpr decltype(auto) operator op(int) cv_ref \
300 noexcept(operator_##name##_scl_exec_noexcept<ScLExec>) \
301 requires \
302 (::std::is_same_v<ScLExec, s_c_l_executor_type cv_ref> \
303 && (operator_##name##_scl_has_exec_override<ScLExec> \
304 || operator_##name##_scl_quals<decltype(SCL_ACCESS_DECLVAL(cv_ref)), int>)) \
305 { \
306 if constexpr (operator_##name##_scl_has_exec_override<ScLExec>) \
307 { \
308 return ::std::remove_cvref_t<ScLExec>::operator_##name( \
309 SCL_EXECUTOR_ACCESS(cv_ref)); \
310 } \
311 else \
312 { \
313 return ::std::remove_cvref_t<ScLExec>::execute(SCL_EXECUTOR_ACCESS(cv_ref), \
314 [](auto && scl_e) -> decltype(auto) { \
315 return ::std::remove_cvref_t<ScLExec>::access(::std::forward<decltype(scl_e)>(scl_e)) \
316 .operator op(int{}); \
317 }, SCL_EXECUTOR_ACCESS(cv_ref)); \
318 } \
319 }
320
359#define SCL_REFLECT_PREFIX_UNARY_OPERATOR(op, name) \
360 SCL_REFLECT_OPERATOR_QUALS(SCL_FORWARD(op), name) \
361 SCL_REFLECT_OPERATOR_EXEC_HELPERS(name) \
362 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &) \
363 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &&) \
364 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &) \
365 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &&) \
366 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &) \
367 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &&) \
368 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &) \
369 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &&)
370
385#define SCL_REFLECT_MEMBER_PREFIX_UNARY_OPERATOR(op, name) \
386 SCL_REFLECT_OPERATOR_QUALS(SCL_FORWARD(op), name) \
387 SCL_REFLECT_OPERATOR_EXEC_HELPERS(name) \
388 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &) \
389 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &&) \
390 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &) \
391 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &&) \
392 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &) \
393 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &&) \
394 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &) \
395 SCL_REFLECT_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &&)
396
418#define SCL_REFLECT_POSTFIX_UNARY_OPERATOR(op, name) \
419 SCL_REFLECT_OPERATOR_QUALS(SCL_FORWARD(op), name) \
420 SCL_REFLECT_OPERATOR_EXEC_HELPERS(name) \
421 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &) \
422 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &&) \
423 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &) \
424 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &&) \
425 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &) \
426 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &&) \
427 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &) \
428 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &&)
429
443#define SCL_REFLECT_MEMBER_POSTFIX_UNARY_OPERATOR(op, name) \
444 SCL_REFLECT_OPERATOR_QUALS(SCL_FORWARD(op), name) \
445 SCL_REFLECT_OPERATOR_EXEC_HELPERS(name) \
446 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &) \
447 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &&) \
448 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &) \
449 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &&) \
450 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &) \
451 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &&) \
452 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &) \
453 SCL_REFLECT_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &&)
454
526#define SCL_REFLECT_BINARY_OPERATOR(op, name) \
527 SCL_REFLECT_COMBINED_OPERATOR_IMPL(SCL_FORWARD(op), name)
528
548#define SCL_REFLECT_MEMBER_BINARY_OPERATOR(op, name) \
549 SCL_REFLECT_OPERATOR_IMPL(SCL_FORWARD(op), name)
550
567#define SCL_REFLECT_OPERATOR_WITH_ARGUMENTS(op, name) \
568 SCL_REFLECT_OPERATOR_IMPL(SCL_FORWARD(op), name)
569
570// ============================================================================
571// Hidden-friend operator reflection macros
572// ============================================================================
573//
574// These are the friend-function ("hidden friend") analogues of the member-
575// operator macros above. The generated overloads are free functions defined
576// with the `friend` keyword inside the enclosing class body, so they are:
577//
578// • only findable via Argument-Dependent Lookup (ADL), not via
579// unqualified or qualified member lookup;
580// • invisible to `w.operator op(...)` call syntax.
581//
582// The wrapper is passed as an explicit first parameter `scl_self` with the
583// same cv-ref qualifier that would be applied to `*this` in the member
584// counterpart. Access to the executor goes through
585// `SCL_FRIEND_EXECUTOR_ACCESS` (defined in access.h) rather than through
586// `*this`; the wrapped value is resolved via `Executor::value` inside the
587// execute dispatch.
588//
589// The class-level helper constructs (QUALS, CALLER, EXEC_HELPERS) are
590// identical to those generated by the member variants — do not invoke both
591// the member and friend macro for the same `name` in the same class body,
592// as that would produce duplicate static member definitions.
593//
594// Note: `operator[]` and `operator()` must be non-static member functions
595// in C++20, so there is no `SCL_REFLECT_FRIEND_OPERATOR_WITH_ARGUMENTS`.
596
608#define SCL_REFLECT_FRIEND_OPERATOR_EXECUTOR_OVERRIDE_BASE(op, name, cv_ref) \
609 template <typename ScLExec = s_c_l_executor_type cv_ref, typename... ScLArgs> \
610 friend constexpr decltype(auto) operator op( \
611 s_c_l_type cv_ref scl_self, ScLArgs &&... scl_args) \
612 noexcept(operator_##name##_scl_exec_noexcept<ScLExec, ScLArgs...>) \
613 requires \
614 (::std::is_same_v<ScLExec, s_c_l_executor_type cv_ref> \
615 && operator_##name##_scl_has_exec_override<ScLExec, ScLArgs...>) \
616 { \
617 return ::std::remove_cvref_t<ScLExec>::operator_##name( \
618 SCL_FRIEND_EXECUTOR_ACCESS(scl_self, cv_ref), \
619 ::std::forward<ScLArgs>(scl_args)...); \
620 }
621
632#define SCL_REFLECT_FRIEND_OPERATOR_BASE(op, name, cv_ref) \
633 noexcept(noexcept(SCL_FRIEND_EXECUTE_OVERRIDED_NX(SCL_FORWARD(operator op), cv_ref))) \
634 requires \
635 (!operator_##name##_scl_has_exec_override<s_c_l_executor_type cv_ref, ScLArgs...> && \
636 requires \
637 { \
638 SCL_ACCESS_DECLVAL(cv_ref).operator op( \
639 ::scl::wrapper_cast(::std::declval<ScLArgs>())...); \
640 } && operator_##name##_scl_quals<decltype(SCL_ACCESS_DECLVAL(cv_ref)), \
641 decltype(::scl::wrapper_cast(::std::declval<ScLArgs>()))...>) \
642 { \
643 return SCL_FRIEND_EXECUTE_OVERRIDED(SCL_FORWARD(operator op), scl_self, cv_ref); \
644 }
645
656#define SCL_REFLECT_FRIEND_TEMPLATE_OPERATOR_BASE(name, caller, cv_ref) \
657 noexcept(noexcept(SCL_FRIEND_EXECUTE_TEMPLATE_OVERRIDED_NX(caller, cv_ref))) \
658 requires \
659 requires \
660 { \
661 caller::template call<ScLParam, ScLParams...>( \
662 SCL_ACCESS_DECLVAL(cv_ref), ::std::declval<ScLArgs>()...); \
663 } && operator_##name##_scl_template_quals<ScLParam, ScLParams...> \
664 ::template value<decltype(SCL_ACCESS_DECLVAL(cv_ref)), \
665 decltype(::scl::wrapper_cast(::std::declval<ScLArgs>()))...> \
666 { \
667 return SCL_FRIEND_EXECUTE_TEMPLATE_OVERRIDED(caller, scl_self, cv_ref); \
668 }
669
679#define SCL_REFLECT_FRIEND_OPERATOR_HELPER(op, name, caller, cv_ref) \
680 SCL_REFLECT_FRIEND_OPERATOR_EXECUTOR_OVERRIDE_BASE(SCL_FORWARD(op), name, cv_ref) \
681 template <typename... ScLArgs> \
682 friend constexpr decltype(auto) operator op( \
683 s_c_l_type cv_ref scl_self, ScLArgs &&... scl_args) \
684 SCL_REFLECT_FRIEND_OPERATOR_BASE(SCL_FORWARD(op), name, cv_ref) \
685 template <typename ScLParam, typename... ScLParams, typename... ScLArgs> \
686 friend constexpr decltype(auto) operator op( \
687 s_c_l_type cv_ref scl_self, ScLArgs &&... scl_args) \
688 SCL_REFLECT_FRIEND_TEMPLATE_OPERATOR_BASE(name, caller, cv_ref)
689
696#define SCL_REFLECT_FRIEND_OPERATOR_IMPL(op, name) \
697 SCL_REFLECT_OPERATOR_QUALS(SCL_FORWARD(op), name) \
698 SCL_REFLECT_OPERATOR_CALLER(SCL_FORWARD(op), name) \
699 SCL_REFLECT_OPERATOR_EXEC_HELPERS(name) \
700 SCL_REFLECT_FRIEND_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, &) \
701 SCL_REFLECT_FRIEND_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, &&) \
702 SCL_REFLECT_FRIEND_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, const &) \
703 SCL_REFLECT_FRIEND_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, const &&) \
704 SCL_REFLECT_FRIEND_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, volatile &) \
705 SCL_REFLECT_FRIEND_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, volatile &&) \
706 SCL_REFLECT_FRIEND_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, const volatile &) \
707 SCL_REFLECT_FRIEND_OPERATOR_HELPER(SCL_FORWARD(op), name, operator_##name##_scl_caller, const volatile &&)
708
719#define SCL_REFLECT_FRIEND_PREFIX_UNARY_OPERATOR_BASE(op, name, cv_ref) \
720 template <typename ScLExec = s_c_l_executor_type cv_ref> \
721 friend constexpr decltype(auto) operator op(s_c_l_type cv_ref scl_self) \
722 noexcept(operator_##name##_scl_exec_noexcept<ScLExec>) \
723 requires \
724 (::std::is_same_v<ScLExec, s_c_l_executor_type cv_ref> \
725 && (operator_##name##_scl_has_exec_override<ScLExec> \
726 || operator_##name##_scl_quals<decltype(SCL_ACCESS_DECLVAL(cv_ref))>)) \
727 { \
728 if constexpr (operator_##name##_scl_has_exec_override<ScLExec>) \
729 { \
730 return ::std::remove_cvref_t<ScLExec>::operator_##name( \
731 SCL_FRIEND_EXECUTOR_ACCESS(scl_self, cv_ref)); \
732 } \
733 else \
734 { \
735 return ::std::remove_cvref_t<ScLExec>::execute( \
736 SCL_FRIEND_EXECUTOR_ACCESS(scl_self, cv_ref), \
737 [](auto && scl_e) -> decltype(auto) { \
738 return ::std::remove_cvref_t<ScLExec>::access(::std::forward<decltype(scl_e)>(scl_e)) \
739 .operator op(); \
740 }, SCL_FRIEND_EXECUTOR_ACCESS(scl_self, cv_ref)); \
741 } \
742 }
743
754#define SCL_REFLECT_FRIEND_POSTFIX_UNARY_OPERATOR_BASE(op, name, cv_ref) \
755 template <typename ScLExec = s_c_l_executor_type cv_ref> \
756 friend constexpr decltype(auto) operator op(s_c_l_type cv_ref scl_self, int) \
757 noexcept(operator_##name##_scl_exec_noexcept<ScLExec>) \
758 requires \
759 (::std::is_same_v<ScLExec, s_c_l_executor_type cv_ref> \
760 && (operator_##name##_scl_has_exec_override<ScLExec> \
761 || operator_##name##_scl_quals<decltype(SCL_ACCESS_DECLVAL(cv_ref)), int>)) \
762 { \
763 if constexpr (operator_##name##_scl_has_exec_override<ScLExec>) \
764 { \
765 return ::std::remove_cvref_t<ScLExec>::operator_##name( \
766 SCL_FRIEND_EXECUTOR_ACCESS(scl_self, cv_ref)); \
767 } \
768 else \
769 { \
770 return ::std::remove_cvref_t<ScLExec>::execute( \
771 SCL_FRIEND_EXECUTOR_ACCESS(scl_self, cv_ref), \
772 [](auto && scl_e) -> decltype(auto) { \
773 return ::std::remove_cvref_t<ScLExec>::access(::std::forward<decltype(scl_e)>(scl_e)) \
774 .operator op(int{}); \
775 }, SCL_FRIEND_EXECUTOR_ACCESS(scl_self, cv_ref)); \
776 } \
777 }
778
794#define SCL_REFLECT_REVERSE_COMBINED_HELPERS(op, name) \
795 template <typename ScLLhs, typename ScLValue> \
796 static constexpr bool operator_##name##_scl_reverse_viable() noexcept \
797 { \
798 return requires(ScLLhs && scl_l, ScLValue && scl_v) \
799 { static_cast<ScLLhs &&>(scl_l) op static_cast<ScLValue &&>(scl_v); }; \
800 }
801
827#define SCL_REFLECT_REVERSE_FRIEND_OPERATOR_BASE(op, name, cv_ref) \
828 template <typename ScLLhs> \
829 friend constexpr decltype(auto) operator op( \
830 ScLLhs && scl_lhs, s_c_l_type cv_ref scl_self) \
831 noexcept(noexcept(SCL_FRIEND_REVERSE_EXECUTE_NX(SCL_FORWARD(op), cv_ref))) \
832 requires \
833 (!::scl::feature::is_wrapper_v<::std::remove_cvref_t<ScLLhs>> \
834 && !::std::is_same_v<::std::remove_cvref_t<ScLLhs>, \
835 ::std::remove_cvref_t<s_c_l_type>> \
836 && operator_##name##_scl_reverse_viable<ScLLhs, \
837 decltype(SCL_ACCESS_DECLVAL(cv_ref))>()) \
838 { \
839 return SCL_FRIEND_REVERSE_EXECUTE(SCL_FORWARD(op), scl_self, scl_lhs, cv_ref); \
840 }
841
853#define SCL_REFLECT_COMBINED_OPERATOR_IMPL(op, name) \
854 SCL_REFLECT_OPERATOR_IMPL(SCL_FORWARD(op), name) \
855 SCL_REFLECT_REVERSE_COMBINED_HELPERS(SCL_FORWARD(op), name) \
856 SCL_REFLECT_REVERSE_FRIEND_OPERATOR_BASE(SCL_FORWARD(op), name, &) \
857 SCL_REFLECT_REVERSE_FRIEND_OPERATOR_BASE(SCL_FORWARD(op), name, &&) \
858 SCL_REFLECT_REVERSE_FRIEND_OPERATOR_BASE(SCL_FORWARD(op), name, const &) \
859 SCL_REFLECT_REVERSE_FRIEND_OPERATOR_BASE(SCL_FORWARD(op), name, const &&) \
860 SCL_REFLECT_REVERSE_FRIEND_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &) \
861 SCL_REFLECT_REVERSE_FRIEND_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &&) \
862 SCL_REFLECT_REVERSE_FRIEND_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &) \
863 SCL_REFLECT_REVERSE_FRIEND_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &&)
864
897#define SCL_REFLECT_FRIEND_BINARY_OPERATOR(op, name) \
898 SCL_REFLECT_FRIEND_OPERATOR_IMPL(SCL_FORWARD(op), name)
899
918#define SCL_REFLECT_FRIEND_PREFIX_UNARY_OPERATOR(op, name) \
919 SCL_REFLECT_OPERATOR_QUALS(SCL_FORWARD(op), name) \
920 SCL_REFLECT_OPERATOR_EXEC_HELPERS(name) \
921 SCL_REFLECT_FRIEND_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &) \
922 SCL_REFLECT_FRIEND_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &&) \
923 SCL_REFLECT_FRIEND_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &) \
924 SCL_REFLECT_FRIEND_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &&) \
925 SCL_REFLECT_FRIEND_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &) \
926 SCL_REFLECT_FRIEND_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &&) \
927 SCL_REFLECT_FRIEND_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &) \
928 SCL_REFLECT_FRIEND_PREFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &&)
929
948#define SCL_REFLECT_FRIEND_POSTFIX_UNARY_OPERATOR(op, name) \
949 SCL_REFLECT_OPERATOR_QUALS(SCL_FORWARD(op), name) \
950 SCL_REFLECT_OPERATOR_EXEC_HELPERS(name) \
951 SCL_REFLECT_FRIEND_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &) \
952 SCL_REFLECT_FRIEND_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, &&) \
953 SCL_REFLECT_FRIEND_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &) \
954 SCL_REFLECT_FRIEND_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const &&) \
955 SCL_REFLECT_FRIEND_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &) \
956 SCL_REFLECT_FRIEND_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, volatile &&) \
957 SCL_REFLECT_FRIEND_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &) \
958 SCL_REFLECT_FRIEND_POSTFIX_UNARY_OPERATOR_BASE(SCL_FORWARD(op), name, const volatile &&)
959
960// clang-format on
Internal accessor macros for executor and value access in reflected methods.
Compile-time predicate macro for cv-ref qualifier detection.
Macro for declaring the wrapper type used by reflection macros.
Executor type traits: interface detection and noexcept helpers.