4#ifndef _Stroika_Foundation_Common_Concept_h_
5#define _Stroika_Foundation_Common_Concept_h_ 1
7#include "Stroika/Foundation/StroikaPreComp.h"
17#include "Stroika/Foundation/Common/Common.h"
18#include "Stroika/Foundation/Common/ConceptsBase.h"
96 template <
typename CLASS_TYPE,
typename RETURN_TYPE,
typename... ARGS>
97 struct FunctionTraits<RETURN_TYPE (CLASS_TYPE::*) (ARGS...) const> {
101 static inline constexpr size_t kArity =
sizeof...(ARGS);
106 using result_type = RETURN_TYPE;
117 using type =
typename std::tuple_element<i, std::tuple<ARGS...>>::type;
125 using arg_t =
typename arg<i>::type;
133 using type =
typename conditional_t<(i <
sizeof...(ARGS)), tuple_element<i, tuple<ARGS...>>, Private_::void_type>::type;
139 using ArgOrVoid_t =
typename ArgOrVoid<i>::type;
145 template <
typename F,
typename... Args>
147 {
noexcept (f (args...)) };
151 template <
typename T>
153 requires { []<
typename Rep,
typename Period> (type_identity<chrono::duration<Rep, Period>>) {}(type_identity<T> ()); };
154 static_assert (not IDuration<float>);
157 template <
typename T>
159 requires { []<
typename CLOCK,
typename DURATION> (type_identity<chrono::time_point<CLOCK, DURATION>>) {}(type_identity<T> ()); };
160 static_assert (not ITimePoint<float>);
174 template <
typename T,
typename... U>
180 template <
typename T>
187 template <
typename...>
192 concept _Boolean_testable_impl = convertible_to<_Ty, bool>;
200 { !
static_cast<_Ty&&
> (__t) } -> Private_::_Boolean_testable_impl;
209 template <
class _Ty1,
class _Ty2>
214 static_assert (not equality_comparable_with<nullopt_t, optional<int>>);
222 template <
class FROM,
class TO>
227 template <
typename OT>
228 concept IOptional = same_as<remove_cvref_t<OT>, std::optional<typename OT::value_type>>;
229 static_assert (IOptional<std::optional<int>>);
230 static_assert (not IOptional<int>);
233#if qCompilerAndStdLib_template_concept_matcher_requires_Buggy
234 template <
typename T1,
typename T2 =
void>
235 struct is_shared_ptr_ : std::false_type {};
236 template <
typename T1>
237 struct is_shared_ptr_<shared_ptr<T1>> : std::true_type {};
238 template <
typename T1,
typename T2 =
void>
239 struct is_pair_ : std::false_type {};
240 template <
typename T1,
typename T2>
241 struct is_pair_<pair<T1, T2>> : std::true_type {};
242 template <
typename... ARGS>
243 struct is_variant_ : std::false_type {};
244 template <
typename... ARGS>
245 struct is_variant_<variant<ARGS...>> : std::true_type {};
252 template <
typename T>
254#if qCompilerAndStdLib_template_concept_matcher_requires_Buggy
255 Private_::is_pair_<T>::value
259 []<
typename T1,
typename T2> (pair<T1, T2>) {}(t)
268 template <
typename T>
270#if qCompilerAndStdLib_template_concept_matcher_requires_Buggy
271 Private_::is_shared_ptr_<T>::value
276 []<
typename T1> (shared_ptr<T1>) {}(t)
285 template <
typename T, std::
size_t N>
286 concept has_tuple_element =
requires (T t) {
287 typename std::tuple_element_t<N, std::remove_const_t<T>>;
288 { get<N> (t) } -> std::convertible_to<const std::tuple_element_t<N, T>&>;
297 template <
typename T>
298 concept ITuple = !std::is_reference_v<T> &&
requires (T t) {
299 typename std::tuple_size<T>::type;
300 requires std::derived_from<std::tuple_size<T>, std::integral_constant<std::size_t, std::tuple_size_v<T>>>;
301 } && []<std::size_t... N> (std::index_sequence<N...>) {
302 return (Private_::has_tuple_element<T, N> && ...);
303 }(std::make_index_sequence<std::tuple_size_v<T>> ());
308 template <
typename T>
310#if qCompilerAndStdLib_template_concept_matcher_requires_Buggy
311 Private_::is_variant_<T>::value
315 []<
typename... TYPES> (variant<TYPES...>) {}(t)
330 template <
typename T>
332 template <
typename TEST_ARGUMENT>
333 using Test = conditional_t<convertible_to<TEST_ARGUMENT, T>, true_type, false_type>;
343 template <
typename T>
345 template <
typename TEST_ARGUMENT>
346 using Test = conditional_t<constructible_from<TEST_ARGUMENT, T>, true_type, false_type>;
360 template <
typename T>
362 { t.size () } -> std::convertible_to<size_t>;
366 template <
typename T>
367 concept HasEq_ =
requires (T t) {
368 { t == t } -> std::convertible_to<bool>;
370 template <
typename T>
371 constexpr inline bool HasEq_v_ = HasEq_<T>;
372 template <
typename T,
typename U>
373 constexpr inline bool HasEq_v_<std::pair<T, U>> = HasEq_v_<T> and HasEq_v_<U>;
374 template <
typename... Ts>
375 constexpr inline bool HasEq_v_<std::tuple<Ts...>> = (HasEq_v_<Ts> and ...);
376 template <
typename T>
377 constexpr bool HasUsableEqualToOptimization ()
383 if constexpr (Private_::HasEq_v_<T>) {
384 struct EqualToEmptyTester_ : equal_to<T> {
388 return sizeof (EqualToEmptyTester_) ==
sizeof (
int);
398 template <
typename T>
413 template <
typename T>
417 template <
typename T,
typename =
void>
418 struct ExtractValueType {
421 template <IHasValueType T>
422 struct ExtractValueType<T> {
423 using type =
typename T::value_type;
425 template <
typename T>
426 struct ExtractValueType<const T*,
void> {
429 template <
typename T>
430 struct ExtractValueType<T*,
void> {
444 template <
typename T>
456 template <
bool B,
typename T>
458 static constexpr bool value = B;
461 template <
typename HEAD,
typename... TAIL>
462 struct Select : std::conditional_t<HEAD::value, HEAD, Select<TAIL...>> {};
463 template <
typename T>
467 template <
bool B,
typename T>
468 struct Select<Case<B, T>> {
470 static_assert (B,
"!");
473 template <
typename HEAD,
typename... TAIL>
474 using Select_t =
typename Select<HEAD, TAIL...>::type;
480 DISABLE_COMPILER_MSC_WARNING_START (4996);
481 DISABLE_COMPILER_GCC_WARNING_START (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
482 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
483 template <
typename T>
484 [[deprecated (
"Since Stroika v3.0d1, use IEqualToOptimizable concept")]]
constexpr bool HasUsableEqualToOptimization ()
486 return IEqualToOptimizable<T>;
489 template <
typename T>
490 [[deprecated (
"Since Stroika v3.0d1, use require expression")]]
constexpr inline bool has_plus_v =
requires (T t) {
494 template <
typename From,
typename To>
495 struct is_explicitly_convertible {
496 template <
typename T>
499 template <
typename F,
typename T>
500 static constexpr auto test (
int) ->
decltype (f (
static_cast<T
> (declval<F> ())),
true)
505 template <
typename F,
typename T>
506 static constexpr auto test (...) ->
bool
511 static bool const value = test<From, To> (0);
514 template <
typename From,
typename To>
515 [[deprecated (
"Since Stroika v3.0d1 - not sure any point - probalyuse convertible or constructible concepts")]]
constexpr inline bool is_explicitly_convertible_v =
516 Private_::is_explicitly_convertible<From, To>::value;
518 template <
typename T>
519 [[deprecated (
"Since Stroika v3.0d1, use IHasSizeMethod")]]
constexpr inline bool has_size_v = IHasSizeMethod<T>;
522 template <
typename T>
523 using has_beginend_t =
decltype (
static_cast<bool> (begin (declval<T&> ()) != end (declval<T&> ())));
525 template <
typename T>
526 [[deprecated (
"Since Stroika v3.0d1, use std::ranges::range (probably - roughly same)")]]
constexpr inline bool has_beginend_v =
527 is_detected_v<Private_::has_beginend_t, T>;
530 template <
typename T>
531 using has_minus_t =
decltype (std::declval<T> () - std::declval<T> ());
533 template <
typename T>
534 [[deprecated (
"Since Stroika v3.0d1, use something else, either requires statment, or random_access_iterator for "
535 "example")]]
constexpr inline bool has_minus_v = is_detected_v<Private_::has_minus_t, T>;
536 template <
typename T,
typename U>
537 [[deprecated (
"Since Stroika v3.0d1, use something else, either requires statment, or random_access_iterator for "
538 "example")]]
constexpr inline bool has_minus_v<std::pair<T, U>> = has_minus_v<T> and has_minus_v<U>;
539 template <
typename... Ts>
540 [[deprecated (
"Since Stroika v3.0d1, use something else, either requires statment, or random_access_iterator for "
541 "example")]]
constexpr inline bool has_minus_v<std::tuple<Ts...>> = (has_minus_v<Ts> and ...);
543 template <
typename T>
544 using has_neq_t =
decltype (
static_cast<bool> (std::declval<T> () != std::declval<T> ()));
546 template <
typename T>
547 [[deprecated (
"Since Stroika v3.0d1, use equality_comparable (cuz in C++20 basically same) concept")]]
constexpr inline bool has_neq_v =
548 is_detected_v<Private_::has_neq_t, T>;
549 template <
typename T,
typename U>
550 [[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>> =
551 has_neq_v<T> and has_neq_v<U>;
552 template <
typename... Ts>
553 [[deprecated (
"Since Stroika v3.0d1, use equality_comparable (cuz in C++20 basically same) concept")]]
constexpr inline bool has_neq_v<std::tuple<Ts...>> =
554 (has_neq_v<Ts> and ...);
556 template <
typename T>
557 [[deprecated (
"Since Stroika v3.0d1, use equality_comparable concept")]]
constexpr inline bool has_eq_v = equality_comparable<T>;
559 template <
typename T>
560 [[deprecated (
"Since Stroika v3.0d1, use totally_ordered concept")]]
constexpr inline bool has_lt_v = totally_ordered<T>;
562 template <
typename T>
563 [[deprecated (
"Since Stroika v3.0d1, use IHasValueType concept")]]
constexpr inline bool has_value_type_v = IHasValueType<T>;
564 template <
typename T>
565 [[deprecated (
"Since Stroika v3.0d1, use https://en.cppreference.com/w/cpp/concepts/equality_comparable")]]
constexpr bool EqualityComparable ()
567 return equality_comparable<T>;
570 template <
typename T>
571 [[deprecated (
"Since Stroika v3.0d1, use https://en.cppreference.com/w/cpp/concepts/totally_ordered - NOT SAME THING AT ALL, BUT "
572 "CLOSEST IN STANDARD")]]
constexpr bool
573 LessThanComparable ()
580 template <
typename T>
581 struct is_callable_impl_ {
583 typedef char (&yes)[1];
584 typedef char (&no)[2];
589 struct Derived : T, Fallback {};
591 template <
typename U, U>
595 static yes test (...);
597 template <
typename C>
598 static no test (Check<
void (Fallback::*) (), &C::operator()>*);
601 static const bool value =
sizeof (test<Derived> (0)) ==
sizeof (yes);
603 template <
typename T>
604 using is_callable = conditional_t<is_class_v<T>, is_callable_impl_<T>, false_type>;
606 template <
typename T>
607 [[deprecated (
"Since Stroika v3.0d1, use https://en.cppreference.com/w/cpp/concepts/invocable")]]
constexpr bool is_callable_v =
608 Private_::is_callable<T>::value;
609 template <
typename ITERABLE>
610 [[deprecated (
"Since Stroika v3.0d1, use ranges::range")]]
constexpr bool IsIterable_v =
611 has_beginend_v<ITERABLE> and not same_as<ExtractValueType_t<ITERABLE>,
void>;
616 template <
typename ITERABLE_OF_T,
typename T>
617 struct IsIterableOfT_Impl2_ {
618 template <
typename X,
typename USE_ITERABLE = ITERABLE_OF_T,
619 bool ITER_RESULT_CONVERTIBLE_TO_T = is_convertible_v<decltype (*begin (declval<USE_ITERABLE&> ())), T>>
620 static auto check (
const X& x)
621 -> conditional_t<is_detected_v<has_beginend_t, ITERABLE_OF_T> and ITER_RESULT_CONVERTIBLE_TO_T, substitution_succeeded<T>, substitution_failure>;
622 static substitution_failure check (...);
623 using type =
decltype (check (declval<T> ()));
625 template <
typename ITERABLE_OF_T,
typename T>
626 using IsIterableOfT_t = integral_constant<bool, not same_as<typename IsIterableOfT_Impl2_<ITERABLE_OF_T, T>::type, substitution_failure>>;
628 template <
typename ITERABLE_OF_T,
typename T>
629 [[deprecated (
"Since Stroika v3.0d1 use Traversal::IIterableOfTo concept")]]
constexpr bool IsIterableOfT_v =
630 Private_::IsIterableOfT_t<ITERABLE_OF_T, T>::value;
633 template <
typename T,
typename =
void>
635 static constexpr bool value =
false;
637 template <
typename T>
638 struct is_iterator<T, enable_if_t<!same_as<typename iterator_traits<T>::value_type, void>>> {
639 static constexpr bool value =
true;
642 template <
typename T>
643 [[deprecated (
"Since Stroika v3.0d1, use input_iterator, forward_iterator, or some other sort of std iterator concept")]]
constexpr bool IsIterator_v =
644 Private_::is_iterator<remove_cvref_t<T>>::value;
646 template <
typename FUNCTOR_ARG,
typename FUNCTOR>
647 [[deprecated (
"Since Stroika v3.0d1, use std::predicate<F,ARG,ARG>")]]
constexpr bool IsTPredicate ()
649 using T = remove_cvref_t<FUNCTOR_ARG>;
650 if constexpr (is_invocable_v<FUNCTOR, T>) {
651 return std::is_convertible_v<std::invoke_result_t<FUNCTOR, T>,
bool>;
655 template <
typename T>
656 [[deprecated (
"Since Stroika v3.0d1, use three_way_comparable")]]
constexpr inline bool has_spaceship_v = three_way_comparable<T>;
657 DISABLE_COMPILER_MSC_WARNING_END (4996);
658 DISABLE_COMPILER_GCC_WARNING_END (
"GCC diagnostic ignored \"-Wdeprecated-declarations\"");
659 DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wdeprecated-declarations\"");
667#include "Concepts.inl"
handy re-usable concept, with the obvious meaning, and strangely omitted from std-c++ (though used in...
concept - trivial shorthand for variadic same_as A or same_as B, or ...
concept true if integral or floatpoint type 'T'. Not sure why not provided by std c++
Concept checks if the given type T has a const size() method which can be called to return a size_t.
Concept checks if the given type T has a value_type (type) member.
like std::invocable concept, except also requires the invocation doesn't raise exceptions
return true iff argument type T, is std::pair<a,b> for some a/b types
return true iff argument type T, is std::shared_ptr<A> for some A types
Concept ITuple<T> check if T is a tuple.
detect if T is a std::variant<> type.
equality_comparable_with, but less strict - just checks if it can be equality compared!
like convertible_to, but also handling cases where T has an explict CTOR taking From
concept version of std::is_trivially_copyable_v
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...
Extract the number of arguments, return type, and each individual argument type from a lambda or simp...