145
|
1 // <concepts> -*- C++ -*-
|
|
2
|
|
3 // Copyright (C) 2019-2020 Free Software Foundation, Inc.
|
|
4 //
|
|
5 // This file is part of the GNU ISO C++ Library. This library is free
|
|
6 // software; you can redistribute it and/or modify it under the
|
|
7 // terms of the GNU General Public License as published by the
|
|
8 // Free Software Foundation; either version 3, or (at your option)
|
|
9 // any later version.
|
|
10
|
|
11 // This library is distributed in the hope that it will be useful,
|
|
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 // GNU General Public License for more details.
|
|
15
|
|
16 // Under Section 7 of GPL version 3, you are granted additional
|
|
17 // permissions described in the GCC Runtime Library Exception, version
|
|
18 // 3.1, as published by the Free Software Foundation.
|
|
19
|
|
20 // You should have received __a copy of the GNU General Public License and
|
|
21 // __a copy of the GCC Runtime Library Exception along with this program;
|
|
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
23 // <http://www.gnu.org/licenses/>.
|
|
24
|
|
25 /** @file include/concepts
|
|
26 * This is a Standard C++ Library header.
|
|
27 * @ingroup concepts
|
|
28 */
|
|
29
|
|
30 #ifndef _GLIBCXX_CONCEPTS
|
|
31 #define _GLIBCXX_CONCEPTS 1
|
|
32
|
|
33 #if __cplusplus > 201703L && __cpp_concepts
|
|
34
|
|
35 #pragma GCC system_header
|
|
36
|
|
37 /**
|
|
38 * @defgroup concepts Concepts
|
|
39 * @ingroup utilities
|
|
40 *
|
|
41 * Concepts for checking type requirements.
|
|
42 */
|
|
43
|
|
44 #include <type_traits>
|
|
45
|
|
46 namespace std _GLIBCXX_VISIBILITY(default)
|
|
47 {
|
|
48 _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
49
|
|
50 #define __cpp_lib_concepts 201806L
|
|
51
|
|
52 // [concepts.lang], language-related concepts
|
|
53
|
|
54 namespace __detail
|
|
55 {
|
|
56 template<typename _Tp, typename _Up>
|
|
57 concept __same_as = std::is_same_v<_Tp, _Up>;
|
|
58 } // namespace __detail
|
|
59
|
|
60 /// [concept.same], concept same_as
|
|
61 template<typename _Tp, typename _Up>
|
|
62 concept same_as
|
|
63 = __detail::__same_as<_Tp, _Up> && __detail::__same_as<_Up, _Tp>;
|
|
64
|
|
65 /// [concept.derived], concept derived_from
|
|
66 template<typename _Derived, typename _Base>
|
|
67 concept derived_from = __is_base_of(_Base, _Derived)
|
|
68 && is_convertible_v<const volatile _Derived*, const volatile _Base*>;
|
|
69
|
|
70 /// [concept.convertible], concept convertible_to
|
|
71 template<typename _From, typename _To>
|
|
72 concept convertible_to = is_convertible_v<_From, _To>
|
|
73 && requires(add_rvalue_reference_t<_From> (&__f)()) {
|
|
74 static_cast<_To>(__f());
|
|
75 };
|
|
76
|
|
77 /// [concept.commonref], concept common_reference_with
|
|
78 template<typename _Tp, typename _Up>
|
|
79 concept common_reference_with
|
|
80 = same_as<common_reference_t<_Tp, _Up>, common_reference_t<_Up, _Tp>>
|
|
81 && convertible_to<_Tp, common_reference_t<_Tp, _Up>>
|
|
82 && convertible_to<_Up, common_reference_t<_Tp, _Up>>;
|
|
83
|
|
84 /// [concept.common], concept common_with
|
|
85 template<typename _Tp, typename _Up>
|
|
86 concept common_with
|
|
87 = same_as<common_type_t<_Tp, _Up>, common_type_t<_Up, _Tp>>
|
|
88 && requires {
|
|
89 static_cast<common_type_t<_Tp, _Up>>(std::declval<_Tp>());
|
|
90 static_cast<common_type_t<_Tp, _Up>>(std::declval<_Up>());
|
|
91 }
|
|
92 && common_reference_with<add_lvalue_reference_t<const _Tp>,
|
|
93 add_lvalue_reference_t<const _Up>>
|
|
94 && common_reference_with<add_lvalue_reference_t<common_type_t<_Tp, _Up>>,
|
|
95 common_reference_t<
|
|
96 add_lvalue_reference_t<const _Tp>,
|
|
97 add_lvalue_reference_t<const _Up>>>;
|
|
98
|
|
99 // [concepts.arithmetic], arithmetic concepts
|
|
100
|
|
101 template<typename _Tp>
|
|
102 concept integral = is_integral_v<_Tp>;
|
|
103
|
|
104 template<typename _Tp>
|
|
105 concept signed_integral = integral<_Tp> && is_signed_v<_Tp>;
|
|
106
|
|
107 template<typename _Tp>
|
|
108 concept unsigned_integral = integral<_Tp> && !signed_integral<_Tp>;
|
|
109
|
|
110 template<typename _Tp>
|
|
111 concept floating_point = is_floating_point_v<_Tp>;
|
|
112
|
|
113 namespace __detail
|
|
114 {
|
|
115 template<typename _Tp>
|
|
116 using __cref = const remove_reference_t<_Tp>&;
|
|
117
|
|
118 template<typename _Tp>
|
|
119 concept __class_or_enum
|
|
120 = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
|
|
121 } // namespace __detail
|
|
122
|
|
123 /// [concept.assignable], concept assignable_from
|
|
124 template<typename _Lhs, typename _Rhs>
|
|
125 concept assignable_from
|
|
126 = is_lvalue_reference_v<_Lhs>
|
|
127 && common_reference_with<__detail::__cref<_Lhs>, __detail::__cref<_Rhs>>
|
|
128 && requires(_Lhs __lhs, _Rhs&& __rhs) {
|
|
129 { __lhs = static_cast<_Rhs&&>(__rhs) } -> same_as<_Lhs>;
|
|
130 };
|
|
131
|
|
132 /// [concept.destructible], concept destructible
|
|
133 template<typename _Tp>
|
|
134 concept destructible = is_nothrow_destructible_v<_Tp>;
|
|
135
|
|
136 /// [concept.constructible], concept constructible_from
|
|
137 template<typename _Tp, typename... _Args>
|
|
138 concept constructible_from
|
|
139 = destructible<_Tp> && is_constructible_v<_Tp, _Args...>;
|
|
140
|
|
141 /// [concept.defaultinitializable], concept default_initializable
|
|
142 template<typename _Tp>
|
|
143 concept default_initializable = constructible_from<_Tp>
|
|
144 && requires
|
|
145 {
|
|
146 _Tp{};
|
|
147 (void) ::new _Tp;
|
|
148 };
|
|
149
|
|
150 /// [concept.moveconstructible], concept move_constructible
|
|
151 template<typename _Tp>
|
|
152 concept move_constructible
|
|
153 = constructible_from<_Tp, _Tp> && convertible_to<_Tp, _Tp>;
|
|
154
|
|
155 /// [concept.copyconstructible], concept copy_constructible
|
|
156 template<typename _Tp>
|
|
157 concept copy_constructible
|
|
158 = move_constructible<_Tp>
|
|
159 && constructible_from<_Tp, _Tp&> && convertible_to<_Tp&, _Tp>
|
|
160 && constructible_from<_Tp, const _Tp&> && convertible_to<const _Tp&, _Tp>
|
|
161 && constructible_from<_Tp, const _Tp> && convertible_to<const _Tp, _Tp>;
|
|
162
|
|
163 // [concept.swappable], concept swappable
|
|
164
|
|
165 namespace ranges
|
|
166 {
|
|
167 namespace __cust_swap
|
|
168 {
|
|
169 template<typename _Tp> void swap(_Tp&, _Tp&) = delete;
|
|
170
|
|
171 template<typename _Tp, typename _Up>
|
|
172 concept __adl_swap
|
|
173 = (__detail::__class_or_enum<remove_reference_t<_Tp>>
|
|
174 || __detail::__class_or_enum<remove_reference_t<_Up>>)
|
|
175 && requires(_Tp&& __t, _Up&& __u) {
|
|
176 swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u));
|
|
177 };
|
|
178
|
|
179 struct _Swap
|
|
180 {
|
|
181 private:
|
|
182 template<typename _Tp, typename _Up>
|
|
183 static constexpr bool
|
|
184 _S_noexcept()
|
|
185 {
|
|
186 if constexpr (__adl_swap<_Tp, _Up>)
|
|
187 return noexcept(swap(std::declval<_Tp>(), std::declval<_Up>()));
|
|
188 else
|
|
189 return is_nothrow_move_constructible_v<remove_reference_t<_Tp>>
|
|
190 && is_nothrow_move_assignable_v<remove_reference_t<_Tp>>;
|
|
191 }
|
|
192
|
|
193 public:
|
|
194 template<typename _Tp, typename _Up>
|
|
195 requires __adl_swap<_Tp, _Up>
|
|
196 || (same_as<_Tp, _Up> && is_lvalue_reference_v<_Tp>
|
|
197 && move_constructible<remove_reference_t<_Tp>>
|
|
198 && assignable_from<_Tp, remove_reference_t<_Tp>>)
|
|
199 constexpr void
|
|
200 operator()(_Tp&& __t, _Up&& __u) const
|
|
201 noexcept(_S_noexcept<_Tp, _Up>())
|
|
202 {
|
|
203 if constexpr (__adl_swap<_Tp, _Up>)
|
|
204 swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u));
|
|
205 else
|
|
206 {
|
|
207 auto __tmp = static_cast<remove_reference_t<_Tp>&&>(__t);
|
|
208 __t = static_cast<remove_reference_t<_Tp>&&>(__u);
|
|
209 __u = static_cast<remove_reference_t<_Tp>&&>(__tmp);
|
|
210 }
|
|
211 }
|
|
212
|
|
213 template<typename _Tp, typename _Up, size_t _Num>
|
|
214 requires requires(const _Swap& __swap, _Tp& __e1, _Up& __e2) {
|
|
215 __swap(__e1, __e2);
|
|
216 }
|
|
217 constexpr void
|
|
218 operator()(_Tp (&__e1)[_Num], _Up (&__e2)[_Num]) const
|
|
219 noexcept(noexcept(std::declval<const _Swap&>()(*__e1, *__e2)))
|
|
220 {
|
|
221 for (size_t __n = 0; __n < _Num; ++__n)
|
|
222 (*this)(__e1[__n], __e2[__n]);
|
|
223 }
|
|
224 };
|
|
225 } // namespace __cust_swap
|
|
226
|
|
227 inline namespace __cust
|
|
228 {
|
|
229 inline constexpr __cust_swap::_Swap swap{};
|
|
230 } // inline namespace __cust
|
|
231 } // namespace ranges
|
|
232
|
|
233 template<typename _Tp>
|
|
234 concept swappable
|
|
235 = requires(_Tp& __a, _Tp& __b) { ranges::swap(__a, __b); };
|
|
236
|
|
237 template<typename _Tp, typename _Up>
|
|
238 concept swappable_with = common_reference_with<_Tp, _Up>
|
|
239 && requires(_Tp&& __t, _Up&& __u) {
|
|
240 ranges::swap(static_cast<_Tp&&>(__t), static_cast<_Tp&&>(__t));
|
|
241 ranges::swap(static_cast<_Up&&>(__u), static_cast<_Up&&>(__u));
|
|
242 ranges::swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u));
|
|
243 ranges::swap(static_cast<_Up&&>(__u), static_cast<_Tp&&>(__t));
|
|
244 };
|
|
245
|
|
246 // [concepts.object], Object concepts
|
|
247
|
|
248 template<typename _Tp>
|
|
249 concept movable = is_object_v<_Tp> && move_constructible<_Tp>
|
|
250 && assignable_from<_Tp&, _Tp> && swappable<_Tp>;
|
|
251
|
|
252 template<typename _Tp>
|
|
253 concept copyable = copy_constructible<_Tp> && movable<_Tp>
|
|
254 && assignable_from<_Tp&, const _Tp&>;
|
|
255
|
|
256 template<typename _Tp>
|
|
257 concept semiregular = copyable<_Tp> && default_initializable<_Tp>;
|
|
258
|
|
259 // [concepts.compare], comparison concepts
|
|
260
|
|
261 /// [concept.boolean], concept boolean
|
|
262 template<typename _Bp>
|
|
263 concept boolean
|
|
264 = movable<remove_cvref_t<_Bp>>
|
|
265 && requires(__detail::__cref<_Bp> __b1, __detail::__cref<_Bp> __b2,
|
|
266 const bool __a) {
|
|
267 { __b1 } -> convertible_to<bool>;
|
|
268 { !__b1 } -> convertible_to<bool>;
|
|
269 { __b1 && __b2 } -> same_as<bool>;
|
|
270 { __b1 && __a } -> same_as<bool>;
|
|
271 { __a && __b2 } -> same_as<bool>;
|
|
272 { __b1 || __b2 } -> same_as<bool>;
|
|
273 { __b1 || __a } -> same_as<bool>;
|
|
274 { __a || __b2 } -> same_as<bool>;
|
|
275 { __b1 == __b2 } -> convertible_to<bool>;
|
|
276 { __b1 == __a } -> convertible_to<bool>;
|
|
277 { __a == __b2 } -> convertible_to<bool>;
|
|
278 { __b1 != __b2 } -> convertible_to<bool>;
|
|
279 { __b1 != __a } -> convertible_to<bool>;
|
|
280 { __a != __b2 } -> convertible_to<bool>;
|
|
281 };
|
|
282
|
|
283 // [concept.equalitycomparable], concept equality_comparable
|
|
284
|
|
285 namespace __detail
|
|
286 {
|
|
287 template<typename _Tp, typename _Up>
|
|
288 concept __weakly_eq_cmp_with
|
|
289 = requires(__detail::__cref<_Tp> __t, __detail::__cref<_Up> __u) {
|
|
290 { __t == __u } -> boolean;
|
|
291 { __t != __u } -> boolean;
|
|
292 { __u == __t } -> boolean;
|
|
293 { __u != __t } -> boolean;
|
|
294 };
|
|
295 } // namespace __detail
|
|
296
|
|
297 template<typename _Tp>
|
|
298 concept equality_comparable = __detail::__weakly_eq_cmp_with<_Tp, _Tp>;
|
|
299
|
|
300 template<typename _Tp, typename _Up>
|
|
301 concept equality_comparable_with
|
|
302 = equality_comparable<_Tp> && equality_comparable<_Up>
|
|
303 && common_reference_with<__detail::__cref<_Tp>, __detail::__cref<_Up>>
|
|
304 && equality_comparable<common_reference_t<__detail::__cref<_Tp>,
|
|
305 __detail::__cref<_Up>>>
|
|
306 && __detail::__weakly_eq_cmp_with<_Tp, _Up>;
|
|
307
|
|
308 // [concept.totallyordered], concept totally_ordered
|
|
309 template<typename _Tp>
|
|
310 concept totally_ordered
|
|
311 = equality_comparable<_Tp>
|
|
312 && requires(__detail::__cref<_Tp> __a, __detail::__cref<_Tp> __b) {
|
|
313 { __a < __b } -> boolean;
|
|
314 { __a > __b } -> boolean;
|
|
315 { __a <= __b } -> boolean;
|
|
316 { __a >= __b } -> boolean;
|
|
317 };
|
|
318
|
|
319 template<typename _Tp, typename _Up>
|
|
320 concept totally_ordered_with
|
|
321 = totally_ordered<_Tp> && totally_ordered<_Up>
|
|
322 && common_reference_with<__detail::__cref<_Tp>, __detail::__cref<_Up>>
|
|
323 && totally_ordered<common_reference_t<__detail::__cref<_Tp>,
|
|
324 __detail::__cref<_Up>>>
|
|
325 && equality_comparable_with<_Tp, _Up>
|
|
326 && requires(__detail::__cref<_Tp> __t, __detail::__cref<_Up> __u) {
|
|
327 { __t < __u } -> boolean;
|
|
328 { __t > __u } -> boolean;
|
|
329 { __t <= __u } -> boolean;
|
|
330 { __t >= __u } -> boolean;
|
|
331 { __u < __t } -> boolean;
|
|
332 { __u > __t } -> boolean;
|
|
333 { __u <= __t } -> boolean;
|
|
334 { __u >= __t } -> boolean;
|
|
335 };
|
|
336
|
|
337 template<typename _Tp>
|
|
338 concept regular = semiregular<_Tp> && equality_comparable<_Tp>;
|
|
339
|
|
340 // [concepts.callable], callable concepts
|
|
341
|
|
342 /// [concept.invocable], concept invocable
|
|
343 template<typename _Fn, typename... _Args>
|
|
344 concept invocable = is_invocable_v<_Fn, _Args...>;
|
|
345
|
|
346 /// [concept.regularinvocable], concept regular_invocable
|
|
347 template<typename _Fn, typename... _Args>
|
|
348 concept regular_invocable = invocable<_Fn, _Args...>;
|
|
349
|
|
350 /// [concept.predicate], concept predicate
|
|
351 template<typename _Fn, typename... _Args>
|
|
352 concept predicate = regular_invocable<_Fn, _Args...>
|
|
353 && boolean<invoke_result_t<_Fn, _Args...>>;
|
|
354
|
|
355 /// [concept.relation], concept relation
|
|
356 template<typename _Rel, typename _Tp, typename _Up>
|
|
357 concept relation
|
|
358 = predicate<_Rel, _Tp, _Tp> && predicate<_Rel, _Up, _Up>
|
|
359 && predicate<_Rel, _Tp, _Up> && predicate<_Rel, _Up, _Tp>;
|
|
360
|
|
361 /// [concept.equiv], concept equivalence_relation
|
|
362 template<typename _Rel, typename _Tp, typename _Up>
|
|
363 concept equivalence_relation = relation<_Rel, _Tp, _Up>;
|
|
364
|
|
365 /// [concept.strictweakorder], concept strict_weak_order
|
|
366 template<typename _Rel, typename _Tp, typename _Up>
|
|
367 concept strict_weak_order = relation<_Rel, _Tp, _Up>;
|
|
368
|
|
369 _GLIBCXX_END_NAMESPACE_VERSION
|
|
370 } // namespace
|
|
371 #endif // C++2a
|
|
372
|
|
373 #endif /* _GLIBCXX_CONCEPTS */
|