|
- /*!
- * \file /utl/concepts/stl.h
- * \brief STL's Concepts
- */
- #ifndef __utl_concepts_stl_h__
- #define __utl_concepts_stl_h__
-
- #include <utl/core/impl.h>
- #include <utl/meta/meta.h>
- #include <utl/utility/invoke.h>
-
- #include <utl/concepts/defines.h>
-
- /*!
- * \brief
- * STL's core language concepts
- *
- * We provide std concepts in case host's stl does not provide them yet.
- *
- * For more information \see https://en.cppreference.com/w/cpp/concepts
- */
- //! @{
- namespace utl {
-
- template <typename T>
- using remove_cvref_t = std::remove_cv_t< std::remove_reference_t<T> >;
-
- template <typename T>
- using cref_ = const std::remove_reference_t<T>&;
-
- template <typename T>
- using _ref_t = std::add_lvalue_reference_t<T>;
-
- template <typename _T1, typename _T2, typename _Ret =_T1>
- using use_if_same_t = meta::eval<
- meta::enable_if<
- meta::same_<_T1, _T2>::value, _Ret
- >
- >;
-
-
- /*!
- * Same
- */
- template <class T, class U>
- _utlConcept Same = meta::same_<T, U>::value;
-
- // template<class T>
- // _utlConcept Decayed = Same<T, std::decay_t<T>>;
-
- /*!
- * DerivedFrom
- */
- template <class Derived, class Base>
- _utlConcept DerivedFrom =
- std::is_base_of<Base, Derived>::value &&
- std::is_convertible<const volatile Derived*, const volatile Base*>::value;
-
-
- /*!
- * ConvertibleTo
- */
- template <class From, class To>
- #if CXX_CONCEPTS
- _utlConcept ConvertibleTo =
- std::is_convertible<From, To>::value &&
- requires(From (&f)()) {
- static_cast<To>(f());
- };
- #else
- _utlConcept ConvertibleTo = std::is_convertible<From, To>::value;
- #endif
-
- /*!
- * Common Reference
- */
- //! @{
- namespace common_impl {
- //! \see https://ericniebler.github.io/std/wg21/D0022.html
- // ========== common reference ===========
- template<class T, class U>
- using __cond_res =
- decltype(false ? std::declval<T(&)()>()() : std::declval<U(&)()>()());
-
- template<class From>
- struct __copy_cv_ {
- static_assert(!std::is_reference<From>::value);
- template<class To> using apply = To;
- };
- template<class From>
- struct __copy_cv_<const From> {
- template<class To> using apply = const To;
- };
- template<class From>
- struct __copy_cv_<volatile From> {
- template<class To> using apply = volatile To;
- };
- template<class From>
- struct __copy_cv_<const volatile From> {
- template<class To> using apply = const volatile To;
- };
- template<class From, class To>
- using __copy_cv = meta::invoke<__copy_cv_<From>, To>;
-
- // CREF [meta.trans.other]/2.1
- template<class T>
- using __cref = std::add_lvalue_reference_t<const std::remove_reference_t<T>>;
-
- // COMMON_REF [meta.trans.other]/2
- template<class T, class U, class = void>
- struct __common_ref_ {
- static_assert(std::is_reference<T>::value, "");
- static_assert(std::is_reference<U>::value, "");
- };
-
- template<class T, class U>
- using __common_ref = meta::eval<__common_ref_<T, U>>;
-
- // [meta.trans.other]/2.5
- template<class T, class U>
- using __lref_res = __cond_res<
- __copy_cv<T, U> &,
- __copy_cv<U, T> &
- >;
-
- // [meta.trans.other]/2.6
- template<class T, class U, class R = __common_ref<T&, U&>>
- using __rref_res = std::remove_reference_t<R>&&;
-
- template<class T, class U>
- struct __common_ref_<T&, U&,
- meta::void_t<__lref_res<T, U>,
- meta::when<std::is_reference<__lref_res<T, U>>::value>> > {
- using type = __lref_res<T, U>;
- };
-
- template<class T, class U>
- struct __common_ref_<T&&, U&&,
- meta::void_t<__common_ref<T&, U&>,
- meta::when<ConvertibleTo<T&&, __rref_res<T, U>>>,
- meta::when<ConvertibleTo<U&&, __rref_res<T, U>>>> > {
- using type = __rref_res<T, U>;
- };
-
- // [meta.trans.other]/2.7
- template<class T, class U>
- struct __common_ref_<T&&, U&,
- meta::void_t<__common_ref<const T&, U&>,
- meta::when<ConvertibleTo<T&&, __common_ref<const T&, U&>>>> > {
- using type = __common_ref<const T&, U&>;
- };
-
- // [meta.trans.other]/2.8
- template<class T, class U>
- struct __common_ref_<T&, U&&,
- meta::void_t<__common_ref<T&, const U&>,
- meta::when<ConvertibleTo<U&&, __common_ref<T&, const U&>>>> > {
- using type = __common_ref<T&, const U&>;
- };
-
- template<class>
- struct __xref {
- template<class U> using apply = U;
- };
- template<class T>
- struct __xref<const T> {
- template<class U> using apply = const U;
- };
- template<class T>
- struct __xref<volatile T> {
- template<class U> using apply = volatile U;
- };
- template<class T>
- struct __xref<const volatile T> {
- template<class U> using apply = const volatile U;
- };
- template<class T>
- struct __xref<T&> {
- template<class U> using apply =
- std::add_lvalue_reference_t<meta::invoke<__xref<T>, U>>;
- };
- template<class T>
- struct __xref<T&&> {
- template<class U> using apply =
- std::add_rvalue_reference_t<meta::invoke<__xref<T>, U>>;
- };
-
- template<class,
- class,
- template<class> class,
- template<class> class
- >
- struct basic_common_reference { };
-
- template<class T, class U>
- using __basic_common_reference_t = meta::eval<
- basic_common_reference<
- remove_cvref_t<T>,
- remove_cvref_t<U>,
- __xref<T>::template apply,
- __xref<U>::template apply
- >
- >;
-
- template<class...>
- struct common_reference {};
-
- template<class... Ts>
- using common_reference_t = meta::eval<
- common_reference<Ts...>
- >;
-
- // [meta.trans.other]/5.2
- template<class T>
- struct common_reference<T> {
- using type = T;
- };
-
- // [meta.trans.other]/5.3.4
- template<class T, class U, class...>
- struct __common_reference3
- : std::common_type<T, U> {};
-
- // [meta.trans.other]/5.3.3
- template<class T, class U>
- struct __common_reference3<T, U,
- meta::void_t<__cond_res<T, U>>> {
- using type = __cond_res<T, U>;
- };
-
- template<class T, class U, class...>
- struct __common_reference2
- : __common_reference3<T, U> {};
-
- // [meta.trans.other]/5.3.2
- template<class T, class U>
- struct __common_reference2<T, U,
- meta::void_t<__basic_common_reference_t<T, U>>> {
- using type = __basic_common_reference_t<T, U>;
- };
-
- template <class T, class U, class...>
- struct __common_reference
- : __common_reference2<T, U> { };
-
- template <class T, class U>
- struct __common_reference<T, U,
- meta::when<std::is_reference<T>::value && std::is_reference<U>::value>> {
- using type = __common_ref<T, U>;
- };
-
- template<class T, class U>
- struct common_reference<T, U> : __common_reference<T, U> { };
-
- // [meta.trans.other]/5.4
- template<class T, class U, class V, class... W>
- //requires requires { typename common_reference_t<T, U>; }
- struct common_reference<T, U, V, W...>
- : common_reference <
- common_reference_t<T, U>, V, W...
- > {};
- }
-
- template<typename...Ts>
- using common_reference = common_impl::common_reference<Ts...>;
-
- template<typename... Ts>
- using common_reference_t = meta::eval<
- common_reference<Ts...>
- >;
-
- //! @}
-
-
- //FIXME: CommonReference needs better implementation
- template <class T, class U>
- _utlConcept CommonReference =
- Same<common_reference_t<T, U>, common_reference_t<U, T>> &&
- ConvertibleTo<T, common_reference_t<T, U>> &&
- ConvertibleTo<U, common_reference_t<T, U>>;
-
-
- // != std::Common on CommonReference
- template <class T, class U>
- _utlConcept Common =
- #if CXX_CONCEPTS
- Same<std::common_type_t<T, U>, std::common_type_t<U, T>> &&
- requires {
- static_cast<std::common_type_t<T, U>>(std::declval<T>());
- static_cast<std::common_type_t<T, U>>(std::declval<U>());
- };
- // } &&
- // CommonReference<
- // std::add_lvalue_reference_t<const T>,
- // std::add_lvalue_reference_t<const U>> &&
- // CommonReference<
- // std::add_lvalue_reference_t<std::common_type_t<T, U>>,
- // std::common_reference_t<
- // std::add_lvalue_reference_t<const T>,
- // std::add_lvalue_reference_t<const U>
- // >
- // >;
- #else
- // meta::and_ <
- Same<std::common_type_t<T, U>, std::common_type_t<U, T>>; //>
- // meta::bool_<CommonReference<
- // std::add_lvalue_reference_t<const T>,
- // std::add_lvalue_reference_t<const U>
- // >>,
- // meta::bool_< CommonReference<
- // std::add_lvalue_reference_t<std::common_type_t<T, U>>,
- // common_reference_t<
- // std::add_lvalue_reference_t<const T>,
- // std::add_lvalue_reference_t<const U>
- // >
- // >>
- // >::value;
- #endif
-
- /*!
- * Integral
- */
- template <class T>
- _utlConcept Integral = std::is_integral<T>::value;
-
- /*!
- * Signed Integral
- */
- template <class T>
- _utlConcept SignedIntegral = Integral<T> && std::is_signed<T>::value;
-
- /*!
- * Unsigned Integral
- */
- template <class T>
- _utlConcept UnsignedIntegral = Integral<T> && !std::is_signed<T>::value;
-
-
- template <typename T>
- _utlConcept MoveAssignable = std::is_move_assignable<T>::value;
-
- template <typename T>
- _utlConcept CopyAssignable = std::is_copy_assignable<T>::value;
-
- /*!
- * Assignable
- * \note != std:: on CommonReference
- */
- template<class LHS, class RHS>
- _utlConcept Assignable =
- #if CXX_CONCEPTS
- std::is_lvalue_reference<LHS>::value &&
- // CommonReference<
- // const std::remove_reference_t<L>&,
- // const std::remove_reference_t<R>&> &&
- requires(LHS lhs, RHS&& rhs) {
- lhs = std::forward<RHS>(rhs);
- requires Same<
- decltype(lhs = std::forward<RHS>(rhs)), LHS
- >;
- };
- #else
- std::is_assignable<LHS, RHS>::value;
- #endif
-
- /*!
- * Swappable, SwappableWith
- */
- //! @{
- #if CXX_VER < CXX_VER_STD_17
- namespace swappable_with_impl {
- struct is_swappable_with_ {
- // can apply std::swap
- template<typename _Tp,
- typename _Up,
- typename
- = decltype(std::swap(std::declval<_Tp&>(), std::declval<_Up&>())),
- typename
- = decltype(std::swap(std::declval<_Up&>(), std::declval<_Tp&>()))>
- static meta::true_ check(int);
- // can not apply std::swap
- template<typename, typename> static meta::false_ check(...);
- };
- }
- template <typename _Tp, typename _Up>
- struct is_swappable_with
- : swappable_with_impl::is_swappable_with_ {
- using type = decltype(check<_Tp, _Up>(0));
- };
- #else
- template<typename Tp>
- using is_swappable = std::is_swappable<Tp>;
- template<typename T, typename U>
- using is_swappable_with = std::is_swappable_with<T, U>;
- #endif
-
- // != std:: on CommonReference
- template<class T, class U>
- _utlConcept SwappableWith =
- is_swappable_with<T, T>::type::value &&
- is_swappable_with<U, U>::type::value &&
- is_swappable_with<T, U>::type::value &&
- is_swappable_with<U, T>::type::value;
- // std::CommonReference<
- // const std::remove_reference_t<T>&,
- // const std::remove_reference_t<U>&
- // >;
-
- // != std:: we use is_swappable_with now is_swappable
- template<class T>
- _utlConcept Swappable = is_swappable_with<T, T>::type::value;
- //! @}
-
- /*!
- * Destructible
- */
- template <class T>
- _utlConcept Destructible = std::is_nothrow_destructible<T>::value;
-
- /*!
- * Constructible
- */
- template <class T, class... Args>
- _utlConcept Constructible =
- Destructible<T> && std::is_constructible<T, Args...>::value;
- /*!
- * DefaultConstructible
- */
- template <class T>
- _utlConcept DefaultConstructible = Constructible<T>;
-
- /*!
- * MoveConstructible
- * \note
- * Another approach would be std::is_move_constructible<T>::value;
- */
- template<class T>
- _utlConcept MoveConstructible =
- Constructible<T, T> && ConvertibleTo<T, T>;
-
- /*!
- * CopyConstructible
- */
- template <class T>
- _utlConcept CopyConstructible =
- MoveConstructible<T> &&
- Constructible<T, _ref_t<T>> && ConvertibleTo<_ref_t<T>, T> &&
- Constructible<T, const _ref_t<T>> && ConvertibleTo<const _ref_t<T>, T> &&
- Constructible<T, const T> && ConvertibleTo<const T, T>;
-
- /*!
- * Movable
- */
- template <class T>
- _utlConcept Movable =
- std::is_object<T>::value &&
- MoveConstructible<T> &&
- Assignable<_ref_t<T>, T> &&
- Swappable<T>;
-
-
- /*!
- * Copyable
- */
- template <class T>
- _utlConcept Copyable =
- CopyConstructible<T> &&
- Movable<T> &&
- Assignable<_ref_t<T>, const _ref_t<T>>;
-
-
- /*!
- * Boolean
- */
- #if CXX_CONCEPTS
- template <class B>
- _utlConcept Boolean =
- Movable<remove_cvref_t<B>> &&
- requires(const std::remove_reference_t<B>& b1,
- const std::remove_reference_t<B>& b2, const bool a) {
- requires ConvertibleTo<const std::remove_reference_t<B>&, bool>;
- !b1; requires ConvertibleTo<decltype(!b1), bool>;
- b1 && a; requires Same<decltype(b1 && a), bool>;
- b1 || a; requires Same<decltype(b1 || a), bool>;
- b1 && b2; requires Same<decltype(b1 && b2), bool>;
- a && b2; requires Same<decltype(a && b2), bool>;
- b1 || b2; requires Same<decltype(b1 || b2), bool>;
- a || b2; requires Same<decltype(a || b2), bool>;
- b1 == b2; requires ConvertibleTo<decltype(b1 == b2), bool>;
- b1 == a; requires ConvertibleTo<decltype(b1 == a), bool>;
- a == b2; requires ConvertibleTo<decltype(a == b2), bool>;
- b1 != b2; requires ConvertibleTo<decltype(b1 != b2), bool>;
- b1 != a; requires ConvertibleTo<decltype(b1 != a), bool>;
- a != b2; requires ConvertibleTo<decltype(a != b2), bool>;
- };
- #else
- namespace details {
- // template <typename B> using try_op_not_ = decltype(!std::declval<cref_<B>>());
- // template <typename B> using try_op_eq_ = decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>());
- // template <typename B> using try_op_neq_ = decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>());
- // template <typename B> using try_op_and_ = decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>());
- // template <typename B> using try_op_or_ = decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>());
- //
- // template <typename B>
- // struct is_boolean__ {
- // using type = meta::and_ <
- // meta::is_detected<B, try_op_not_>,
- // meta::is_detected<B, try_op_eq_>,
- // meta::is_detected<B, try_op_neq_>,
- // meta::is_detected<B, try_op_and_>,
- // meta::is_detected<B, try_op_or_>
- // >;
- // };
-
- template <typename B, typename = void>
- struct is_boolean_ {
- using type = meta::false_;
- };
-
- template <typename B>
- struct is_boolean_ <B, meta::void_t<
- meta::use_if_same_t<bool, decltype(!std::declval<cref_<B>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>())>
- >> {
- using type = meta::true_;
- };
-
- template <typename B>
- using is_boolean_t = meta::eval <
- is_boolean_<B>
- >;
- }
- template <class B>
- _utlConcept Boolean =
- Movable<remove_cvref_t<B>> &&
- //ConvertibleTo<const std::remove_reference_t<B>&, bool> &&
- ConvertibleTo<const _ref_t<B>, bool> &&
- Same<meta::true_, details::is_boolean_t<B>>;
- #endif
-
-
- namespace details {
- template <typename T, typename U, typename = void>
- struct is_weakly_equality_comparable_with_ {
- using type = meta::false_;
- };
-
- template <typename T, typename U>
- struct is_weakly_equality_comparable_with_<T, U, meta::void_t<
- meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() == std::declval<cref_<U>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() != std::declval<cref_<U>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() == std::declval<cref_<T>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() != std::declval<cref_<T>>())>
- >> {
- using type = meta::true_;
- };
-
- template <typename T, typename U>
- using is_weakly_equality_comparable_with_t = meta::eval<
- is_weakly_equality_comparable_with_ <T, U>
- >;
- }
-
- template <class T, class U>
- _utlConcept WeaklyEqualityComparableWith =
- #if CXX_CONCEPTS
- requires(const std::remove_reference_t<T>& t,
- const std::remove_reference_t<U>& u) {
- t == u; requires Boolean<decltype(t == u)>;
- t != u; requires Boolean<decltype(t != u)>;
- u == t; requires Boolean<decltype(u == t)>;
- u != t; requires Boolean<decltype(u != t)>;
- };
- #else
- Same<meta::true_, details::is_weakly_equality_comparable_with_t<T, U>>;
- #endif
-
- template <class T>
- _utlConcept EqualityComparable = WeaklyEqualityComparableWith<T, T>;
-
- template <class T, class U>
- _utlConcept EqualityComparableWith =
- EqualityComparable<T> &&
- EqualityComparable<U> &&
- // CommonReference<
- // const std::remove_reference_t<T>&,
- // const std::remove_reference_t<U>&> &&
- // EqualityComparable<
- // common_reference_t<
- // const std::remove_reference_t<T>&,
- // const std::remove_reference_t<U>&>> &&
- WeaklyEqualityComparableWith<T, U>;
-
-
-
- #if CXX_CONCEPTS
- template <class T>
- _utlConcept StrictTotallyOrdered =
- EqualityComparable<T> &&
- requires(const std::remove_reference_t<T>& a,
- const std::remove_reference_t<T>& b) {
- a < b; requires Boolean<decltype(a < b)>;
- a > b; requires Boolean<decltype(a > b)>;
- a <= b; requires Boolean<decltype(a <= b)>;
- a >= b; requires Boolean<decltype(a >= b)>;
- };
- #else
- namespace details {
- template <typename T, typename = void>
- struct is_strict_totally_ordered_ {
- using type = meta::false_;
- };
-
- template <typename T>
- struct is_strict_totally_ordered_ <T, meta::void_t <
- meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() < std::declval<cref_<T>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() > std::declval<cref_<T>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() <= std::declval<cref_<T>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() >= std::declval<cref_<T>>())>
- >> {
- using type = meta::true_;
- };
-
- template <typename T>
- using is_strict_totally_ordered_t = meta::eval <
- is_strict_totally_ordered_<T>
- >;
- }
- template <class T>
- _utlConcept StrictTotallyOrdered =
- EqualityComparable<T> &&
- Same <meta::true_, details::is_strict_totally_ordered_t<T>>;
- #endif
-
- #if CXX_CONCEPTS
- template <class T, class U>
- _utlConcept StrictTotallyOrderedWith =
- StrictTotallyOrdered<T> &&
- StrictTotallyOrdered<U> &&
- // CommonReference<
- // const std::remove_reference_t<T>&,
- // const std::remove_reference_t<U>&
- // > &&
- // StrictTotallyOrdered<
- // common_reference_t<
- // const std::remove_reference_t<T>&,
- // const std::remove_reference_t<U>&
- // >
- // > &&
- EqualityComparableWith<T, U> &&
- requires(const std::remove_reference_t<T>& t,
- const std::remove_reference_t<U>& u) {
- t < u; requires Boolean<decltype(t < u)>;
- t > u; requires Boolean<decltype(t > u)>;
- t <= u; requires Boolean<decltype(t <= u)>;
- t >= u; requires Boolean<decltype(t >= u)>;
- u < t; requires Boolean<decltype(u < t)>;
- u > t; requires Boolean<decltype(u > t)>;
- u <= t; requires Boolean<decltype(u <= t)>;
- u >= t; requires Boolean<decltype(u >= t)>;
- };
- #else
- namespace details {
- template <typename T, typename U, typename = void>
- struct is_strict_totally_ordered_with_ {
- using type = meta::false_;
- };
-
- template <typename T, typename U>
- struct is_strict_totally_ordered_with_ <T, U, meta::void_t <
- meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() < std::declval<cref_<U>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() > std::declval<cref_<U>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() <= std::declval<cref_<U>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() >= std::declval<cref_<U>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() < std::declval<cref_<T>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() > std::declval<cref_<T>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() <= std::declval<cref_<T>>())>,
- meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() >= std::declval<cref_<T>>())>
- >> {
- using type = meta::true_;
- };
-
- template <typename T, typename U>
- using is_strict_totally_ordered_with_t = meta::eval <
- is_strict_totally_ordered_with_<T, U>
- >;
- }
- template <class T, class U>
- _utlConcept StrictTotallyOrderedWith =
- StrictTotallyOrdered<T> &&
- StrictTotallyOrdered<U> &&
- EqualityComparableWith<T, U> &&
- Same <meta::true_, details::is_strict_totally_ordered_with_t<T, U>>;
- #endif
-
- /*!
- * Semiregular
- */
- template <class T>
- _utlConcept Semiregular = Copyable<T> && DefaultConstructible<T>;
-
- /*!
- * Regular
- */
- template <class T>
- _utlConcept Regular = Semiregular<T> && EqualityComparable<T>;
-
- /*!
- * Scalar
- */
- template<class T>
- _utlConcept Scalar =
- std::is_scalar<T>::value && Regular<T>;
-
- /*!
- * Arithmetic
- */
- template<class T>
- _utlConcept Arithmetic =
- std::is_arithmetic<T>::value && Scalar<T> && StrictTotallyOrdered<T>;
-
- /*!
- * FloatingPoint
- */
- template<class T>
- _utlConcept FloatingPoint =
- std::is_floating_point<T>::value && Arithmetic<T>;
-
- /*!
- * Invocable
- */
- template <class F, class... Args>
- _utlConcept Invocable = is_invocable<F, Args...>::value;
- // requires(F&& f, Args&&... args) {
- // invoke(std::forward<F>(f), std::forward<Args>(args)...);
- // };
-
- template< class F, class... Args >
- _utlConcept RegularInvocable = Invocable<F, Args...>;
-
- template < class F, class... Args >
- _utlConcept Predicate =
- RegularInvocable<F, Args...> &&
- Boolean<invoke_result_t<F, Args...>>;
-
- template <class R, class T, class U>
- _utlConcept Relation =
- Predicate<R, T, T> && Predicate<R, U, U> &&
- Predicate<R, T, U> && Predicate<R, U, T>;
-
- template < class R, class T, class U >
- _utlConcept StrictWeakOrder = Relation<R, T, U>;
- }
- //! @}
-
-
-
-
- #endif /* __utl_concepts_stl_h__ */
|