Stroika Library 3.0d23x
 
Loading...
Searching...
No Matches
Concepts.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Common_Concept_h_
5#define _Stroika_Foundation_Common_Concept_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <chrono>
10#include <concepts>
11#include <functional> // needed for std::equal_to
12#include <iterator> // needed for std::begin/std::end calls
13#include <memory>
14#include <optional>
15#include <variant>
16
17#include "Stroika/Foundation/Common/Common.h"
18#include "Stroika/Foundation/Common/ConceptsBase.h"
19
20/*
21 * \file
22 * Miscellaneous type traits and concepts for metaprogramming
23 *
24 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
25 *
26 *
27 USEFUL EXAMPLE:
28 template <IStdPathLike2UNICODEString TOSTRINGABLE>
29 explicit String (TOSTRINGABLE&& s)
30 requires (
31 not IBasicUNICODEStdString<remove_cvref_t<TOSTRINGABLE>> and
32 not requires (TOSTRINGABLE t) {
33 {
34 []<IUNICODECanUnambiguouslyConvertFrom T1> (const T1*) {}(t)
35 };
36 } and
37 not requires (TOSTRINGABLE t) {
38 {
39 []<IUNICODECanUnambiguouslyConvertFrom T1> (const span<const T1>&) {}(t)
40 };
41 } and
42 not requires (TOSTRINGABLE t) {
43 {
44 []<IStdBasicStringCompatibleCharacter T1> (const basic_string_view<T1>&) {}(t)
45 };
46 })
47#if qCompilerAndStdLib_RequiresNotMatchInlineOutOfLineForTemplateClassBeingDefined_Buggy
48 : String{mkSTR_ (forward<TOSTRINGABLE> (s))} {}
49#else
50 ;
51#endif
52
53 */
54
56
57 namespace Private_ {
58 struct void_type {
59 using type = void;
60 };
61 }
62
63 /**
64 * \brief ClassNotFinal
65 */
66 template <typename T>
67 concept ClassNotFinal = not is_final_v<T>;
68
69 /**
70 * \brief concept true if integral or floating-point type 'T'. Not sure why not provided by std c++
71 *
72 * Also note - NOT marked true for arithmetic-like types, like big-num package (perhaps provide another concept for this).
73 */
74 template <typename T>
75 concept IBuiltinArithmetic = is_arithmetic_v<T>;
76
77 /**
78 * \brief Extract the number of arguments, return type, and each individual argument type from a lambda or simple function object.
79 *
80 * \par Example Usage
81 * \code
82 * auto lambda = [](int i) { return long(i*10); };
83 *
84 * using traits = FunctionTraits<decltype(lambda)>;
85 *
86 * static_assert (traits::kArity == 1);
87 * static_assert (same_as<long, traits::result_type>);
88 * static_assert (same_as<int, traits::arg<0>::type>);
89 * \endcode
90 *
91 * CREDITS:
92 * From https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda
93 * https://stackoverflow.com/users/224671/kennytm
94 *
95 * For generic types, directly use the result of the signature of its 'operator()'
96 * Specialize for pointers to member function
97 *
98 * \note this doesn't work for function objects that have templated operator() - such as String::EqualsComparer, since there is no type to extract.
99 */
100 template <typename T>
101 struct FunctionTraits : public FunctionTraits<decltype (&T::operator())> {};
102 template <typename CLASS_TYPE, typename RETURN_TYPE, typename... ARGS>
103 struct FunctionTraits<RETURN_TYPE (CLASS_TYPE::*) (ARGS...) const> {
104 /**
105 * \brief Number of arguments
106 */
107 static inline constexpr size_t kArity = sizeof...(ARGS);
108
109 /**
110 * Function return type.
111 */
112 using result_type = RETURN_TYPE;
113
114 /**
115 * type of the ith 'arg';
116 *
117 * \note UNCLEAR if/how this might work if the function is overloaded...
118 *
119 * \see arg_t, ArgOrVoid, ArgOrVoid_t
120 */
121 template <size_t i>
122 struct arg {
123 using type = typename std::tuple_element<i, std::tuple<ARGS...>>::type;
124 // the i-th argument is equivalent to the i-th tuple element of a tuple
125 // composed of those arguments.
126 };
127
128 /**
129 */
130 template <size_t i>
131 using arg_t = typename arg<i>::type;
132
133 /**
134 * \brief like 'arg' - except that if index > max legal, instead of failing to compile, will return void. Helpful
135 * sometimes in contexts where c++ templates run more code than you might want.
136 */
137 template <size_t i>
138 struct ArgOrVoid {
139 using type = typename conditional_t<(i < sizeof...(ARGS)), tuple_element<i, tuple<ARGS...>>, Private_::void_type>::type;
140 };
141
142 /**
143 */
144 template <size_t i>
145 using ArgOrVoid_t = typename ArgOrVoid<i>::type;
146 };
147
148 /**
149 * \brief like std::invocable concept, except also requires the invocation doesn't raise exceptions
150 */
151 template <typename F, typename... Args>
152 concept INoThrowInvocable = invocable<F, Args...> and requires (F f, Args... args) {
153 { noexcept (f (args...)) };
154 };
155
156 /**
157 * \par Example Usage
158 * \code
159 * static_assert (invocable_r<decltype ([] (int) { return ""; }), const char*, int>);
160 * static_assert (invocable_r<decltype ([] (char*, char*) {}), void, char*, char*>);
161 * \endcode
162 *
163 * \note used STL-style name since so closely related to invocable - which is part of the standard library.
164 */
165 template <typename F, typename R, typename... Args>
166 concept invocable_r = invocable<F, Args...> && convertible_to<invoke_result_t<F, Args...>, R>;
167 static_assert (invocable_r<decltype ([] (int) { return ""; }), const char*, int>);
168 static_assert (invocable_r<decltype ([] (char*, char*) {}), void, char*, char*>);
169
170 // From https://stackoverflow.com/questions/74383254/concept-that-models-only-the-stdchrono-duration-types
171 template <typename T>
172 concept IDuration =
173 requires { []<typename Rep, typename Period> (type_identity<chrono::duration<Rep, Period>>) {}(type_identity<T> ()); };
174 static_assert (not IDuration<float>);
175
176 // From https://stackoverflow.com/questions/74383254/concept-that-models-only-the-stdchrono-duration-types
177 template <typename T>
178 concept ITimePoint =
179 requires { []<typename CLOCK, typename DURATION> (type_identity<chrono::time_point<CLOCK, DURATION>>) {}(type_identity<T> ()); };
180 static_assert (not ITimePoint<float>);
181
182 /**
183 * \brief concept - trivial shorthand for variadic same_as A or same_as B, or ...
184 *
185 * \par Example Usage
186 * \code
187 * template <typename T>
188 * concept IBasicUNICODECodePoint = same_as<remove_cv_t<T>, char8_t> or same_as<remove_cv_t<T>, char16_t> or same_as<remove_cv_t<T>, char32_t>;
189 *
190 * template <typename T>
191 * concept IBasicUNICODECodePoint = Common::IAnyOf<remove_cv_t<T>, char8_t, char16_t, char32_t>;
192 * \endcode
193 */
194 template <typename T, typename... U>
195 concept IAnyOf = (same_as<T, U> or ...);
196
197 /**
198 * \brief concept version of std::is_trivially_copyable_v
199 */
200 template <typename T>
201 concept trivially_copyable = is_trivially_copyable_v<T>;
202
203 /**
204 * A template which ignores its template arguments, and always returns true_type;
205 * NOT crazy - helpful is template metaprogramming.
206 */
207 template <typename...>
208 using True = true_type;
209
210 namespace Private_ {
211 template <class _Ty>
212 concept _Boolean_testable_impl = convertible_to<_Ty, bool>;
213 }
214
215 /**
216 * \brief handy re-usable concept, with the obvious meaning, and strangely omitted from std-c++ (though used in exposition).
217 */
218 template <class _Ty>
219 concept Boolean_testable = Private_::_Boolean_testable_impl<_Ty> && requires (_Ty&& __t) {
220 { !static_cast<_Ty&&> (__t) } -> Private_::_Boolean_testable_impl;
221 };
222
223 /**
224 * \brief equality_comparable_with, but less strict - just checks if it can be equality compared!
225 *
226 * INSPIRATION: https://godbolt.org/z/qevGWKan4
227 * static_assert (equality_comparable_with<nullopt_t, optional<int>>); // note this fails
228 */
229 template <class _Ty1, class _Ty2>
230 concept Weak_Equality_Comparable_With = requires (const remove_reference_t<_Ty1>& __x, const remove_reference_t<_Ty2>& __y) {
231 { __x == __y } -> Boolean_testable;
232 { __x != __y } -> Boolean_testable;
233 };
234 static_assert (not equality_comparable_with<nullopt_t, optional<int>>);
236
237 /**
238 * \brief like convertible_to, but also handling cases where T has an explicit CTOR taking From
239 *
240 * \see https://stackoverflow.com/questions/76547398/stdconvertible-to-failing-to-recognize-explicitly-convertible-types
241 */
242 template <class FROM, class TO>
243 concept explicitly_convertible_to = requires { static_cast<TO> (std::declval<FROM> ()); };
244
245 /**
246 */
247 template <typename OT>
248 concept IOptional = same_as<remove_cvref_t<OT>, std::optional<typename OT::value_type>>;
249 static_assert (IOptional<std::optional<int>>);
250 static_assert (not IOptional<int>);
251
252 namespace Private_ {
253#if qCompilerAndStdLib_template_concept_matcher_requires_Buggy
254 template <typename T1, typename T2 = void>
255 struct is_shared_ptr_ : std::false_type {};
256 template <typename T1>
257 struct is_shared_ptr_<shared_ptr<T1>> : std::true_type {};
258 template <typename T1, typename T2 = void>
259 struct is_pair_ : std::false_type {};
260 template <typename T1, typename T2>
261 struct is_pair_<pair<T1, T2>> : std::true_type {};
262 template <typename... ARGS>
263 struct is_variant_ : std::false_type {};
264 template <typename... ARGS>
265 struct is_variant_<variant<ARGS...>> : std::true_type {};
266#endif
267 }
268
269 /**
270 * \brief return true iff argument type T, is std::pair<a,b> for some a/b types
271 */
272 template <typename T>
273 concept IPair =
274#if qCompilerAndStdLib_template_concept_matcher_requires_Buggy
275 Private_::is_pair_<T>::value
276#else
277 requires (T t) {
278 {
279 []<typename T1, typename T2> (pair<T1, T2>) {}(t)
280 };
281 }
282#endif
283 ;
284
285 /**
286 * \brief return true iff argument type T, is std::shared_ptr<A> for some A types
287 */
288 template <typename T>
289 concept ISharedPtr =
290#if qCompilerAndStdLib_template_concept_matcher_requires_Buggy
291 Private_::is_shared_ptr_<T>::value
292#else
293
294 requires (T t) {
295 {
296 []<typename T1> (shared_ptr<T1>) {}(t)
297 };
298 }
299#endif
300 ;
301 static_assert (ISharedPtr<shared_ptr<int>>);
302 static_assert (not ISharedPtr<int>);
303
304 namespace Private_ {
305 template <typename T, std::size_t N>
306 concept has_tuple_element = requires (T t) {
307 typename std::tuple_element_t<N, std::remove_const_t<T>>;
308 { get<N> (t) } -> std::convertible_to<const std::tuple_element_t<N, T>&>;
309 };
310 }
311
312 /**
313 * \brief Concept ITuple<T> check if T is a tuple.
314 *
315 * based on https://stackoverflow.com/questions/68443804/c20-concept-to-check-tuple-like-types
316 */
317 template <typename T>
318 concept ITuple = !std::is_reference_v<T> && requires (T t) {
319 typename std::tuple_size<T>::type;
320 requires std::derived_from<std::tuple_size<T>, std::integral_constant<std::size_t, std::tuple_size_v<T>>>;
321 } && []<std::size_t... N> (std::index_sequence<N...>) {
322 return (Private_::has_tuple_element<T, N> && ...);
323 }(std::make_index_sequence<std::tuple_size_v<T>> ());
324
325 /**
326 * \brief - detect if T is a std::variant<> type.
327 */
328 template <typename T>
329 concept IVariant =
330#if qCompilerAndStdLib_template_concept_matcher_requires_Buggy
331 Private_::is_variant_<T>::value
332#else
333 requires (T t) {
334 {
335 []<typename... TYPES> (variant<TYPES...>) {}(t)
336 };
337 }
338#endif
339 ;
340 static_assert (not IVariant<int>);
341 static_assert (IVariant<variant<int>>);
342
343 /**
344 * Concepts let you construct a 'template' of one arg from one with two args, but class, and variable templates don't allow
345 * this; but this magic trick of double indirection does allow it. And cannot use concepts as template arguments to another template
346 * sadly, so need this trick...
347 *
348 * The 'test' here just invokes convertible_to<TEST_ARGUMENT, T>
349 */
350 template <typename T>
352 template <typename TEST_ARGUMENT>
353 using Test = conditional_t<convertible_to<TEST_ARGUMENT, T>, true_type, false_type>;
354 };
355
356 /**
357 * Concepts let you construct a 'template' of one arg from one with two args, but class, and variable templates don't allow
358 * this; but this magic trick of double indirection does allow it. And cannot use concepts as template arguments to another template
359 * sadly, so need this trick...
360 *
361 * The 'test' here just invokes constructible_from<TEST_ARGUMENT, T>
362 */
363 template <typename T>
365 template <typename TEST_ARGUMENT>
366 using Test = conditional_t<constructible_from<TEST_ARGUMENT, T>, true_type, false_type>;
367 };
368
369 /**
370 * \brief Concept checks if the given type T has a const size() method which can be called to return a size_t.
371 *
372 * \par Example Usage
373 * \code
374 * if constexpr (IHasSizeMethod<T>) {
375 * T a{};
376 * return a.size ();
377 * }
378 * \endcode
379 */
380 template <typename T>
381 concept IHasSizeMethod = requires (const T& t) {
382 { t.size () } -> std::convertible_to<size_t>;
383 };
384
385 namespace Private_ {
386 template <typename T>
387 concept HasEq_ = requires (T t) {
388 { t == t } -> std::convertible_to<bool>;
389 };
390 template <typename T>
391 constexpr inline bool HasEq_v_ = HasEq_<T>;
392 template <typename T, typename U>
393 constexpr inline bool HasEq_v_<std::pair<T, U>> = HasEq_v_<T> and HasEq_v_<U>;
394 template <typename... Ts>
395 constexpr inline bool HasEq_v_<std::tuple<Ts...>> = (HasEq_v_<Ts> and ...);
396 template <typename T>
397 constexpr bool HasUsableEqualToOptimization ()
398 {
399 // static_assert (Common::IOperatorEq<remove_cvref_t<T>> and ! equality_comparable<T>);
400 // static_assert (not Common::IOperatorEq<T> and equality_comparable<T>);
401 // static_assert (Common::IOperatorEq<remove_cvref_t<T>> == equality_comparable<T>);
402 // @todo figure out why Private_::HasEq_v_ needed and cannot use equality_comparable
403 if constexpr (Private_::HasEq_v_<T>) {
404 struct EqualToEmptyTester_ : equal_to<T> {
405 int a;
406 };
407 // leverage empty base class optimization to see if equal_to contains any real data
408 return sizeof (EqualToEmptyTester_) == sizeof (int);
409 }
410 return false;
411 }
412 }
413
414 /**
415 * Check if equal_to<T> is both well defined, and contains no data. The reason it matters that it contains no data, is because
416 * then one instance is as good as another, and it need not be passed anywhere, opening an optimization opportunity.
417 */
418 template <typename T>
419 concept IEqualToOptimizable = equality_comparable<T> and Private_::HasUsableEqualToOptimization<T> ();
420
421 /**
422 * \brief Concept checks if the given type T has a value_type (type) member
423 *
424 * \par Example Usage
425 * \code
426 * if constexpr (IHasValueType<T>) {
427 * typename T::value_type x;
428 * }
429 * \endcode
430 *
431 * \note this replaces Stroika v2.1 constexpr inline bool has_value_type_v template variable
432 */
433 template <typename T>
434 concept IHasValueType = requires (T t) { typename T::value_type; };
435
436 namespace Private_ {
437 template <typename T, typename = void>
438 struct ExtractValueType {
439 using type = void;
440 };
441 template <IHasValueType T>
442 struct ExtractValueType<T> {
443 using type = typename T::value_type;
444 };
445 template <typename T>
446 struct ExtractValueType<const T*, void> {
447 using type = T;
448 };
449 template <typename T>
450 struct ExtractValueType<T*, void> {
451 using type = T;
452 };
453 }
454
455 /**
456 * \brief Extract the type of elements in a container, or returned by an iterator (value_type) or void it there is no value_type
457 *
458 * \note when known if argument is container or iterator, use std::iter_value_t, or std::ranges::range_value_t
459 *
460 * If the given T has a field value_type, return it; returns void if T has no value_type
461 *
462 * NOTE - similar to std::ranges::range_value_t or std::iter_value_t except works with other types.
463 */
464 template <typename T>
465 using ExtractValueType_t = typename Private_::ExtractValueType<remove_cvref_t<T>>::type;
466
467 /**
468 * from https://stackoverflow.com/questions/32785105/implementing-a-switch-type-trait-with-stdconditional-t-chain-calls
469 * \par Example Usage
470 * \code
471 * using Type = Select_t<Case<false, void>,
472 * Case<false, int>,
473 * Case<true, std::string>>;
474 * \endcode
475 */
476 template <bool B, typename T>
477 struct Case {
478 static constexpr bool value = B;
479 using type = T;
480 };
481 template <typename HEAD, typename... TAIL>
482 struct Select : std::conditional_t<HEAD::value, HEAD, Select<TAIL...>> {};
483 template <typename T>
484 struct Select<T> {
485 using type = T;
486 };
487 template <bool B, typename T>
488 struct Select<Case<B, T>> {
489 // last one had better be true!
490 static_assert (B, "!");
491 using type = T;
492 };
493 template <typename HEAD, typename... TAIL>
494 using Select_t = typename Select<HEAD, TAIL...>::type;
495
496 /////////////////////////////////////////////////////////////
497 ////////////////////// DEPREACTED BELOW /////////////////////
498 /////////////////////////////////////////////////////////////
499
500 DISABLE_COMPILER_MSC_WARNING_START (4996);
501 DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
502 DISABLE_COMPILER_CLANG_WARNING_START ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
503 template <typename T>
504 [[deprecated ("Since Stroika v3.0d1, use IEqualToOptimizable concept")]] constexpr bool HasUsableEqualToOptimization ()
505 {
506 return IEqualToOptimizable<T>;
507 }
508
509 template <typename T>
510 [[deprecated ("Since Stroika v3.0d1, use require expression")]] constexpr inline bool has_plus_v = requires (T t) {
511 { t + t };
512 };
513 namespace Private_ {
514 template <typename From, typename To>
515 struct is_explicitly_convertible {
516 template <typename T>
517 static void f (T);
518
519 template <typename F, typename T>
520 static constexpr auto test (int) -> decltype (f (static_cast<T> (declval<F> ())), true)
521 {
522 return true;
523 }
524
525 template <typename F, typename T>
526 static constexpr auto test (...) -> bool
527 {
528 return false;
529 }
530
531 static bool const value = test<From, To> (0);
532 };
533 }
534 template <typename From, typename To>
535 [[deprecated ("Since Stroika v3.0d1 - not sure any point - probalyuse convertible or constructible concepts")]] constexpr inline bool is_explicitly_convertible_v =
536 Private_::is_explicitly_convertible<From, To>::value;
537
538 template <typename T>
539 [[deprecated ("Since Stroika v3.0d1, use IHasSizeMethod")]] constexpr inline bool has_size_v = IHasSizeMethod<T>;
540
541 namespace Private_ {
542 template <typename T>
543 using has_beginend_t = decltype (static_cast<bool> (begin (declval<T&> ()) != end (declval<T&> ())));
544 }
545 template <typename T>
546 [[deprecated ("Since Stroika v3.0d1, use std::ranges::range (probably - roughly same)")]] constexpr inline bool has_beginend_v =
547 is_detected_v<Private_::has_beginend_t, T>;
548
549 namespace Private_ {
550 template <typename T>
551 using has_minus_t = decltype (std::declval<T> () - std::declval<T> ());
552 }
553 template <typename T>
554 [[deprecated ("Since Stroika v3.0d1, use something else, either requires statment, or random_access_iterator for "
555 "example")]] constexpr inline bool has_minus_v = is_detected_v<Private_::has_minus_t, T>;
556 template <typename T, typename U>
557 [[deprecated ("Since Stroika v3.0d1, use something else, either requires statment, or random_access_iterator for "
558 "example")]] constexpr inline bool has_minus_v<std::pair<T, U>> = has_minus_v<T> and has_minus_v<U>;
559 template <typename... Ts>
560 [[deprecated ("Since Stroika v3.0d1, use something else, either requires statment, or random_access_iterator for "
561 "example")]] constexpr inline bool has_minus_v<std::tuple<Ts...>> = (has_minus_v<Ts> and ...);
562 namespace Private_ {
563 template <typename T>
564 using has_neq_t = decltype (static_cast<bool> (std::declval<T> () != std::declval<T> ()));
565 }
566 template <typename T>
567 [[deprecated ("Since Stroika v3.0d1, use equality_comparable (cuz in C++20 basically same) concept")]] constexpr inline bool has_neq_v =
568 is_detected_v<Private_::has_neq_t, T>;
569 template <typename T, typename U>
570 [[deprecated ("Since Stroika v3.0d1, use equality_comparable (cuz in C++20 basically same) concept")]] constexpr inline bool has_neq_v<std::pair<T, U>> =
571 has_neq_v<T> and has_neq_v<U>;
572 template <typename... Ts>
573 [[deprecated ("Since Stroika v3.0d1, use equality_comparable (cuz in C++20 basically same) concept")]] constexpr inline bool has_neq_v<std::tuple<Ts...>> =
574 (has_neq_v<Ts> and ...);
575
576 template <typename T>
577 [[deprecated ("Since Stroika v3.0d1, use equality_comparable concept")]] constexpr inline bool has_eq_v = equality_comparable<T>;
578
579 template <typename T>
580 [[deprecated ("Since Stroika v3.0d1, use totally_ordered concept")]] constexpr inline bool has_lt_v = totally_ordered<T>;
581
582 template <typename T>
583 [[deprecated ("Since Stroika v3.0d1, use IHasValueType concept")]] constexpr inline bool has_value_type_v = IHasValueType<T>;
584 template <typename T>
585 [[deprecated ("Since Stroika v3.0d1, use https://en.cppreference.com/w/cpp/concepts/equality_comparable")]] constexpr bool EqualityComparable ()
586 {
587 return equality_comparable<T>;
588 }
589
590 template <typename T>
591 [[deprecated ("Since Stroika v3.0d1, use https://en.cppreference.com/w/cpp/concepts/totally_ordered - NOT SAME THING AT ALL, BUT "
592 "CLOSEST IN STANDARD")]] constexpr bool
593 LessThanComparable ()
594 {
595 return has_lt_v<T>;
596 }
597
598 namespace Private_ {
599 // From https://stackoverflow.com/questions/15393938/find-out-if-a-c-object-is-callable
600 template <typename T>
601 struct is_callable_impl_ {
602 private:
603 typedef char (&yes)[1];
604 typedef char (&no)[2];
605
606 struct Fallback {
607 void operator() ();
608 };
609 struct Derived : T, Fallback {};
610
611 template <typename U, U>
612 struct Check;
613
614 template <typename>
615 static yes test (...);
616
617 template <typename C>
618 static no test (Check<void (Fallback::*) (), &C::operator()>*);
619
620 public:
621 static const bool value = sizeof (test<Derived> (0)) == sizeof (yes);
622 };
623 template <typename T>
624 using is_callable = conditional_t<is_class_v<T>, is_callable_impl_<T>, false_type>;
625 }
626 template <typename T>
627 [[deprecated ("Since Stroika v3.0d1, use https://en.cppreference.com/w/cpp/concepts/invocable")]] constexpr bool is_callable_v =
628 Private_::is_callable<T>::value;
629 template <typename ITERABLE>
630 [[deprecated ("Since Stroika v3.0d1, use ranges::range")]] constexpr bool IsIterable_v =
631 has_beginend_v<ITERABLE> and not same_as<ExtractValueType_t<ITERABLE>, void>;
632
633 namespace Private_ {
634
635 // Would be nice to simplify, but my current version of is_detected_v only takes one template parameter, and the std::experimental version not included in VS2k19
636 template <typename ITERABLE_OF_T, typename T>
637 struct IsIterableOfT_Impl2_ {
638 template <typename X, typename USE_ITERABLE = ITERABLE_OF_T,
639 bool ITER_RESULT_CONVERTIBLE_TO_T = is_convertible_v<decltype (*begin (declval<USE_ITERABLE&> ())), T>>
640 static auto check (const X& x)
641 -> conditional_t<is_detected_v<has_beginend_t, ITERABLE_OF_T> and ITER_RESULT_CONVERTIBLE_TO_T, substitution_succeeded<T>, substitution_failure>;
642 static substitution_failure check (...);
643 using type = decltype (check (declval<T> ()));
644 };
645 template <typename ITERABLE_OF_T, typename T>
646 using IsIterableOfT_t = integral_constant<bool, not same_as<typename IsIterableOfT_Impl2_<ITERABLE_OF_T, T>::type, substitution_failure>>;
647 }
648 template <typename ITERABLE_OF_T, typename T>
649 [[deprecated ("Since Stroika v3.0d1 use Traversal::IIterableOfTo concept")]] constexpr bool IsIterableOfT_v =
650 Private_::IsIterableOfT_t<ITERABLE_OF_T, T>::value;
651
652 namespace Private_ {
653 template <typename T, typename = void>
654 struct is_iterator {
655 static constexpr bool value = false;
656 };
657 template <typename T>
658 struct is_iterator<T, enable_if_t<!same_as<typename iterator_traits<T>::value_type, void>>> {
659 static constexpr bool value = true;
660 };
661 }
662 template <typename T>
663 [[deprecated ("Since Stroika v3.0d1, use input_iterator, forward_iterator, or some other sort of std iterator concept")]] constexpr bool IsIterator_v =
664 Private_::is_iterator<remove_cvref_t<T>>::value;
665
666 template <typename FUNCTOR_ARG, typename FUNCTOR>
667 [[deprecated ("Since Stroika v3.0d1, use std::predicate<F,ARG,ARG>")]] constexpr bool IsTPredicate ()
668 {
669 using T = remove_cvref_t<FUNCTOR_ARG>;
670 if constexpr (is_invocable_v<FUNCTOR, T>) {
671 return std::is_convertible_v<std::invoke_result_t<FUNCTOR, T>, bool>;
672 }
673 return false;
674 }
675 template <typename T>
676 [[deprecated ("Since Stroika v3.0d1, use three_way_comparable")]] constexpr inline bool has_spaceship_v = three_way_comparable<T>;
677 DISABLE_COMPILER_MSC_WARNING_END (4996);
678 DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
679 DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wdeprecated-declarations\"");
680}
681
682/*
683 ********************************************************************************
684 ***************************** Implementation Details ***************************
685 ********************************************************************************
686 */
687#include "Concepts.inl"
688
689#endif /*_Stroika_Foundation_Common_Concept_h_ */
handy re-usable concept, with the obvious meaning, and strangely omitted from std-c++ (though used in...
Definition Concepts.h:219
concept - trivial shorthand for variadic same_as A or same_as B, or ...
Definition Concepts.h:195
concept true if integral or floating-point type 'T'. Not sure why not provided by std c++
Definition Concepts.h:75
Concept checks if the given type T has a const size() method which can be called to return a size_t.
Definition Concepts.h:381
Concept checks if the given type T has a value_type (type) member.
Definition Concepts.h:434
like std::invocable concept, except also requires the invocation doesn't raise exceptions
Definition Concepts.h:152
return true iff argument type T, is std::pair<a,b> for some a/b types
Definition Concepts.h:273
return true iff argument type T, is std::shared_ptr<A> for some A types
Definition Concepts.h:289
Concept ITuple<T> check if T is a tuple.
Definition Concepts.h:318
detect if T is a std::variant<> type.
Definition Concepts.h:329
equality_comparable_with, but less strict - just checks if it can be equality compared!
Definition Concepts.h:230
like convertible_to, but also handling cases where T has an explicit CTOR taking From
Definition Concepts.h:243
concept version of std::is_trivially_copyable_v
Definition Concepts.h:201
typename Private_::ExtractValueType< remove_cvref_t< T > >::type ExtractValueType_t
Extract the type of elements in a container, or returned by an iterator (value_type) or void it there...
Definition Concepts.h:465
Extract the number of arguments, return type, and each individual argument type from a lambda or simp...
Definition Concepts.h:101