GMP 0.3.0
Generative Metaprogramming library for C++
Loading...
Searching...
No Matches
named_operator.hpp
Go to the documentation of this file.
1// ___ __ __ ___
2// / __| \/ | _ \ GMP(Generative Metaprogramming)
3// | (_ | |\/| | _/ version 0.3.0
4// \___|_| |_|_| https://github.com/lkimuk/gmp
5//
6// SPDX-FileCopyrightText: 2026 Miles Li <https://www.cppmore.com/>
7// SPDX-License-Identifier: MIT
8//
9// This file is part of the GMP (Generative Metaprogramming) library.
10// Full project source: https://github.com/lkimuk/gmp
11
12#ifndef GMP_META_NAMED_OPERATOR_HPP_
13#define GMP_META_NAMED_OPERATOR_HPP_
14
15#include <concepts>
16#include <functional>
17#include <type_traits>
18#include <tuple>
19#include <utility>
20
21#include <gmp/macro/macro.hpp>
22
23namespace gmp {
24
25namespace detail {
26
37template<typename... Ts>
38struct value_holder {
39 std::tuple<Ts...> values;
40
41 template<typename... Us>
42 requires std::constructible_from<std::tuple<Ts...>, Us&&...>
43 constexpr explicit value_holder(Us&&... us)
44 : values(std::forward<Us>(us)...) {}
45};
46
56template<typename T>
57using named_operator_lhs_storage_t = std::conditional_t<
58 std::is_lvalue_reference_v<T>, T, std::remove_cvref_t<T>>;
59
73template<typename Lhs, typename Func>
74[[nodiscard]]
75constexpr auto bind_named_operator(Lhs&& lhs, value_holder<Func> holder) {
77
79 std::forward<Lhs>(lhs),
80 std::get<0>(std::move(holder.values))
81 );
82}
83
99template<typename Lhs, typename Func, typename Rhs>
100 requires std::invocable<Func&&, Lhs, Rhs&&>
101constexpr decltype(auto) invoke_named_operator(value_holder<Lhs, Func>&& holder, Rhs&& rhs) {
102 auto&& [lhs, func] = holder.values;
103 return std::invoke(std::move(func), std::forward<Lhs>(lhs), std::forward<Rhs>(rhs));
104}
105
106#define GMP_DEFINE_NAMED_OPERATOR_PAIR(pair) \
107 template<typename Lhs, typename Func> \
108 requires std::movable<Func> \
109 constexpr auto operator GMP_GET_TUPLE(0, pair) (Lhs&& lhs, ::gmp::detail::value_holder<Func> holder) { \
110 return ::gmp::detail::bind_named_operator(std::forward<Lhs>(lhs), std::move(holder)); \
111 } \
112 \
113 template<typename Lhs, typename Func, typename Rhs> \
114 requires std::invocable<Func&&, Lhs, Rhs&&> \
115 constexpr decltype(auto) operator GMP_GET_TUPLE(1, pair) ( \
116 ::gmp::detail::value_holder<Lhs, Func>&& holder, Rhs&& rhs) { \
117 return ::gmp::detail::invoke_named_operator(std::move(holder), std::forward<Rhs>(rhs)); \
118 }
119
120#define GMP_TO_PAIR(x) (x, x),
121#define GMP_TO_PAIRS(...) GMP_REMOVE_TRAILING_COMMA(GMP_FOR_EACH(GMP_TO_PAIR, __VA_ARGS__))
122
123#define GMP_GENERATE_NAMED_OPERATOR_PAIRS(...) \
124 GMP_FOR_EACH(GMP_DEFINE_NAMED_OPERATOR_PAIR, __VA_ARGS__)
125#define GMP_GENERATE_NAMED_OPERATOR_IDENTICAL_PAIRS(...) \
126 _GMP_GENERATE_NAMED_OPERATOR_IDENTICAL_PAIRS_MSVC_COMPAT(GMP_TO_PAIRS(__VA_ARGS__))
127#define _GMP_GENERATE_NAMED_OPERATOR_IDENTICAL_PAIRS_MSVC_COMPAT(...) \
128 GMP_FOR_EACH(GMP_DEFINE_NAMED_OPERATOR_PAIR, __VA_ARGS__)
129
130#ifndef GMP_DISABLE_DEFAULT_NAMED_OPERATORS
133#endif
134
135#undef _GMP_GENERATE_NAMED_OPERATOR_IDENTICAL_PAIRS_MSVC_COMPAT
136#undef GMP_GENERATE_NAMED_OPERATOR_IDENTICAL_PAIRS
137#undef GMP_GENERATE_NAMED_OPERATOR_PAIRS
138#undef GMP_TO_PAIRS
139#undef GMP_TO_PAIR
140#undef GMP_DEFINE_NAMED_OPERATOR_PAIR
141
142} // namespace detail
143
184template<typename Func>
185[[nodiscard]]
186constexpr auto make_named_operator(Func&& f) {
187 using func_type = std::remove_cvref_t<Func>;
188
189 return detail::value_holder<func_type>(std::forward<Func>(f));
190}
191
194} // namespace gmp
195
196#endif // GMP_META_NAMED_OPERATOR_HPP_
constexpr auto make_named_operator(Func &&f)
Create a token that lets a callable be used as a named infix operator.
consteval auto enum_values()
Get all enumerator values of an enumeration type at compile-time.
Definition meta.hpp:155
#define GMP_GENERATE_NAMED_OPERATOR_IDENTICAL_PAIRS(...)
#define GMP_GENERATE_NAMED_OPERATOR_PAIRS(...)
Definition lock.hpp:21