mpc
Haskell-like feature supports in C++
single.hpp
Go to the documentation of this file.
1
2#pragma once
3#include <mpc/type_traits.hpp>
5
6// clang-format off
7
8namespace mpc {
14 template <class T, class Tag = void>
15 struct single {
16 private:
17 T instance_{};
18
19 public:
20 // methods:
21 // [x] value_type
22 // [x] ctors
23 // [x] assignment ops
24 // [x] operator<=>
25 // [x] swap
26 // [x] operator*
27 // [x] operator->
28
29 using value_type = T;
30
31 // ctors
32
33 // (1)
34 explicit(not detail::is_implicitly_default_constructible_v<T>)
35 constexpr single()
36 requires std::default_initializable<T> =default;
37
38 // (2)
39 single(const single&) = default;
40
41 // (3)
42 single(single&&) = default;
43
44 // (4)
45 explicit(not std::is_convertible_v<const T&, T>)
46 constexpr single(const T& rhs)
47 requires std::copy_constructible<T>
48 : instance_(rhs) {}
49
50 // (5)
51 template <class U = T>
52 requires std::constructible_from<T, U&&>
53 explicit(not std::is_convertible_v<U, T>)
54 constexpr single(U&& rhs)
55 : instance_(std::forward<U>(rhs)) {}
56
57 // (6)
58 template <tuple_like Tuple>
59 requires (
60 not std::constructible_from<T, Tuple&&> and
61 std::constructible_from<T, detail::copy_reference_t<Tuple, std::tuple_element_t<0, Tuple>>&&>
62 )
63 explicit(not std::is_convertible_v<std::tuple_element_t<0, Tuple>, T>)
64 constexpr single(Tuple&& rhs)
65 : instance_(get<0>(std::forward<Tuple>(rhs))) {}
66
67 // (7)
68 template <class... Args>
69 requires std::constructible_from<T, Args&&...>
70 constexpr single(std::in_place_t, Args&&... args)
71 : instance_(std::forward<Args>(args)...) {}
72
73 // (8)
74 template <class U, class... Args>
75 requires std::constructible_from<T, std::initializer_list<U>, Args&&...>
76 constexpr single(std::in_place_t, std::initializer_list<U> il, Args&&... args)
77 : instance_(il, std::forward<Args>(args)...) {}
78
79 // assignment ops.
80
81 // (1)
82 constexpr single& operator=(const single& rhs)
83 requires std::is_copy_assignable_v<T> {
84 instance_ = *rhs;
85 return *this;
86 }
87
88 // (2)
89 constexpr single& operator=(single&& rhs)
90 noexcept(std::is_nothrow_move_assignable_v<T>)
91 requires std::is_move_assignable_v<T> {
92 instance_ = *std::move(rhs);
93 return *this;
94 }
95
96 // (3)
97 template <std::convertible_to<T> U = T>
98 single& operator=(U&& rhs) {
99 instance_ = std::forward<U>(rhs);
100 return *this;
101 }
102
103 // (4)
104 template <tuple_like Tuple>
105 requires (
106 not std::convertible_to<Tuple, T> and
107 std::convertible_to<std::tuple_element_t<0, Tuple>, T>
108 )
109 constexpr single& operator=(Tuple&& rhs) {
110 instance_ = get<0>(std::forward<Tuple>(rhs));
111 return *this;
112 }
113
114 // operator <=>
115
116 auto operator<=>(const single&) const
117 requires std::equality_comparable<T> = default;
118
119 // swap
120
121 void swap(single& other)
122 noexcept(std::is_nothrow_swappable_v<T>)
123 requires std::swappable<T> {
124 using std::swap;
125 swap(instance_, other.instance_);
126 }
127
128 // operator*
129
130 constexpr decltype(auto) operator*() & {
131 return instance_;
132 }
133
134 constexpr decltype(auto) operator*() const& {
135 return instance_;
136 }
137
138 constexpr decltype(auto) operator*() && {
139 return std::move(instance_);
140 }
141
142 constexpr decltype(auto) operator*() const&& {
143 return std::move(instance_);
144 }
145
146 // operator->
147
148 constexpr auto operator->() {
149 return std::addressof(instance_);
150 }
151
152 constexpr auto operator->() const {
153 return std::addressof(instance_);
154 }
155 }; // struct single
156
157 // grobal methods:
158 // [x] deduction guides
159 // [x] swap
160 // [x] get
161
163 template <class T, class Tag = void>
165
167 template <std::swappable T, class Tag>
169 noexcept(std::is_nothrow_swappable_v<T>) {
170 lhs.swap(rhs);
171 }
172
174 template <std::size_t Idx, class T, class Tag>
175 requires (Idx < 1)
176 constexpr decltype(auto) get(single<T, Tag>& s) {
177 return *s;
178 }
179
181 template <std::size_t Idx, class T, class Tag>
182 requires (Idx < 1)
183 constexpr decltype(auto) get(const single<T, Tag>& s) {
184 return *s;
185 }
186
188 template <std::size_t Idx, class T, class Tag>
189 requires (Idx < 1)
190 constexpr decltype(auto) get(single<T, Tag>&& s) {
191 return *std::move(s);
192 }
193
195 template <std::size_t Idx, class T, class Tag>
196 requires (Idx < 1)
197 constexpr decltype(auto) get(const single<T, Tag>&& s) {
198 return *std::move(s);
199 }
200} // namespace mpc
201
202// tuple-like methods:
203// [x] std::tuple_size
204// [x] std::tuple_element
205
207template <class T, class Tag>
208struct std::tuple_size<mpc::single<T, Tag>> : mpc::index_constant<1> {};
209
211template <std::size_t Idx, class T, class Tag>
212requires (Idx < 1)
213struct std::tuple_element<Idx, mpc::single<T, Tag>> {
214 using type = T;
215};
216
217// clang-format on
void swap(single< T, Tag > &lhs, single< T, Tag > &rhs) noexcept(std::is_nothrow_swappable_v< T >)
swap for single
Definition: single.hpp:168
constexpr decltype(auto) get(single< T, Tag > &s)
get for single
Definition: single.hpp:176
std::integral_constant< std::size_t, N > index_constant
index_constant
Definition: stdfundamental.hpp:24
A class that holds a single value.
Definition: single.hpp:15