Micro template library A library for building device drivers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

763 lines
24 KiB

  1. /*!
  2. * \file /utl/concepts/stl.h
  3. * \brief STL's Concepts
  4. */
  5. #ifndef __utl_concepts_stl_h__
  6. #define __utl_concepts_stl_h__
  7. #include <utl/core/impl.h>
  8. #include <utl/meta/meta.h>
  9. #include <utl/utility/invoke.h>
  10. #include <utl/concepts/defines.h>
  11. /*!
  12. * \brief
  13. * STL's core language concepts
  14. *
  15. * We provide std concepts in case host's stl does not provide them yet.
  16. *
  17. * For more information \see https://en.cppreference.com/w/cpp/concepts
  18. */
  19. //! @{
  20. namespace utl {
  21. template <typename T>
  22. using remove_cvref_t = std::remove_cv_t< std::remove_reference_t<T> >;
  23. template <typename T>
  24. using cref_ = const std::remove_reference_t<T>&;
  25. template <typename T>
  26. using _ref_t = std::add_lvalue_reference_t<T>;
  27. template <typename _T1, typename _T2, typename _Ret =_T1>
  28. using use_if_same_t = meta::eval<
  29. meta::enable_if<
  30. meta::same_<_T1, _T2>::value, _Ret
  31. >
  32. >;
  33. /*!
  34. * Same
  35. */
  36. template <class T, class U>
  37. _utlConcept Same = meta::same_<T, U>::value;
  38. // template<class T>
  39. // _utlConcept Decayed = Same<T, std::decay_t<T>>;
  40. /*!
  41. * DerivedFrom
  42. */
  43. template <class Derived, class Base>
  44. _utlConcept DerivedFrom =
  45. std::is_base_of<Base, Derived>::value &&
  46. std::is_convertible<const volatile Derived*, const volatile Base*>::value;
  47. /*!
  48. * ConvertibleTo
  49. */
  50. template <class From, class To>
  51. #if CXX_CONCEPTS
  52. _utlConcept ConvertibleTo =
  53. std::is_convertible<From, To>::value &&
  54. requires(From (&f)()) {
  55. static_cast<To>(f());
  56. };
  57. #else
  58. _utlConcept ConvertibleTo = std::is_convertible<From, To>::value;
  59. #endif
  60. /*!
  61. * Common Reference
  62. */
  63. //! @{
  64. namespace common_impl {
  65. //! \see https://ericniebler.github.io/std/wg21/D0022.html
  66. // ========== common reference ===========
  67. template<class T, class U>
  68. using __cond_res =
  69. decltype(false ? std::declval<T(&)()>()() : std::declval<U(&)()>()());
  70. template<class From>
  71. struct __copy_cv_ {
  72. static_assert(!std::is_reference<From>::value);
  73. template<class To> using apply = To;
  74. };
  75. template<class From>
  76. struct __copy_cv_<const From> {
  77. template<class To> using apply = const To;
  78. };
  79. template<class From>
  80. struct __copy_cv_<volatile From> {
  81. template<class To> using apply = volatile To;
  82. };
  83. template<class From>
  84. struct __copy_cv_<const volatile From> {
  85. template<class To> using apply = const volatile To;
  86. };
  87. template<class From, class To>
  88. using __copy_cv = meta::invoke<__copy_cv_<From>, To>;
  89. // CREF [meta.trans.other]/2.1
  90. template<class T>
  91. using __cref = std::add_lvalue_reference_t<const std::remove_reference_t<T>>;
  92. // COMMON_REF [meta.trans.other]/2
  93. template<class T, class U, class = void>
  94. struct __common_ref_ {
  95. static_assert(std::is_reference<T>::value, "");
  96. static_assert(std::is_reference<U>::value, "");
  97. };
  98. template<class T, class U>
  99. using __common_ref = meta::eval<__common_ref_<T, U>>;
  100. // [meta.trans.other]/2.5
  101. template<class T, class U>
  102. using __lref_res = __cond_res<
  103. __copy_cv<T, U> &,
  104. __copy_cv<U, T> &
  105. >;
  106. // [meta.trans.other]/2.6
  107. template<class T, class U, class R = __common_ref<T&, U&>>
  108. using __rref_res = std::remove_reference_t<R>&&;
  109. template<class T, class U>
  110. struct __common_ref_<T&, U&,
  111. meta::void_t<__lref_res<T, U>,
  112. meta::when<std::is_reference<__lref_res<T, U>>::value>> > {
  113. using type = __lref_res<T, U>;
  114. };
  115. template<class T, class U>
  116. struct __common_ref_<T&&, U&&,
  117. meta::void_t<__common_ref<T&, U&>,
  118. meta::when<ConvertibleTo<T&&, __rref_res<T, U>>>,
  119. meta::when<ConvertibleTo<U&&, __rref_res<T, U>>>> > {
  120. using type = __rref_res<T, U>;
  121. };
  122. // [meta.trans.other]/2.7
  123. template<class T, class U>
  124. struct __common_ref_<T&&, U&,
  125. meta::void_t<__common_ref<const T&, U&>,
  126. meta::when<ConvertibleTo<T&&, __common_ref<const T&, U&>>>> > {
  127. using type = __common_ref<const T&, U&>;
  128. };
  129. // [meta.trans.other]/2.8
  130. template<class T, class U>
  131. struct __common_ref_<T&, U&&,
  132. meta::void_t<__common_ref<T&, const U&>,
  133. meta::when<ConvertibleTo<U&&, __common_ref<T&, const U&>>>> > {
  134. using type = __common_ref<T&, const U&>;
  135. };
  136. template<class>
  137. struct __xref {
  138. template<class U> using apply = U;
  139. };
  140. template<class T>
  141. struct __xref<const T> {
  142. template<class U> using apply = const U;
  143. };
  144. template<class T>
  145. struct __xref<volatile T> {
  146. template<class U> using apply = volatile U;
  147. };
  148. template<class T>
  149. struct __xref<const volatile T> {
  150. template<class U> using apply = const volatile U;
  151. };
  152. template<class T>
  153. struct __xref<T&> {
  154. template<class U> using apply =
  155. std::add_lvalue_reference_t<meta::invoke<__xref<T>, U>>;
  156. };
  157. template<class T>
  158. struct __xref<T&&> {
  159. template<class U> using apply =
  160. std::add_rvalue_reference_t<meta::invoke<__xref<T>, U>>;
  161. };
  162. template<class,
  163. class,
  164. template<class> class,
  165. template<class> class
  166. >
  167. struct basic_common_reference { };
  168. template<class T, class U>
  169. using __basic_common_reference_t = meta::eval<
  170. basic_common_reference<
  171. remove_cvref_t<T>,
  172. remove_cvref_t<U>,
  173. __xref<T>::template apply,
  174. __xref<U>::template apply
  175. >
  176. >;
  177. template<class...>
  178. struct common_reference {};
  179. template<class... Ts>
  180. using common_reference_t = meta::eval<
  181. common_reference<Ts...>
  182. >;
  183. // [meta.trans.other]/5.2
  184. template<class T>
  185. struct common_reference<T> {
  186. using type = T;
  187. };
  188. // [meta.trans.other]/5.3.4
  189. template<class T, class U, class...>
  190. struct __common_reference3
  191. : std::common_type<T, U> {};
  192. // [meta.trans.other]/5.3.3
  193. template<class T, class U>
  194. struct __common_reference3<T, U,
  195. meta::void_t<__cond_res<T, U>>> {
  196. using type = __cond_res<T, U>;
  197. };
  198. template<class T, class U, class...>
  199. struct __common_reference2
  200. : __common_reference3<T, U> {};
  201. // [meta.trans.other]/5.3.2
  202. template<class T, class U>
  203. struct __common_reference2<T, U,
  204. meta::void_t<__basic_common_reference_t<T, U>>> {
  205. using type = __basic_common_reference_t<T, U>;
  206. };
  207. template <class T, class U, class...>
  208. struct __common_reference
  209. : __common_reference2<T, U> { };
  210. template <class T, class U>
  211. struct __common_reference<T, U,
  212. meta::when<std::is_reference<T>::value && std::is_reference<U>::value>> {
  213. using type = __common_ref<T, U>;
  214. };
  215. template<class T, class U>
  216. struct common_reference<T, U> : __common_reference<T, U> { };
  217. // [meta.trans.other]/5.4
  218. template<class T, class U, class V, class... W>
  219. //requires requires { typename common_reference_t<T, U>; }
  220. struct common_reference<T, U, V, W...>
  221. : common_reference <
  222. common_reference_t<T, U>, V, W...
  223. > {};
  224. }
  225. template<typename...Ts>
  226. using common_reference = common_impl::common_reference<Ts...>;
  227. template<typename... Ts>
  228. using common_reference_t = meta::eval<
  229. common_reference<Ts...>
  230. >;
  231. //! @}
  232. //FIXME: CommonReference needs better implementation
  233. template <class T, class U>
  234. _utlConcept CommonReference =
  235. Same<common_reference_t<T, U>, common_reference_t<U, T>> &&
  236. ConvertibleTo<T, common_reference_t<T, U>> &&
  237. ConvertibleTo<U, common_reference_t<T, U>>;
  238. // != std::Common on CommonReference
  239. template <class T, class U>
  240. _utlConcept Common =
  241. #if CXX_CONCEPTS
  242. Same<std::common_type_t<T, U>, std::common_type_t<U, T>> &&
  243. requires {
  244. static_cast<std::common_type_t<T, U>>(std::declval<T>());
  245. static_cast<std::common_type_t<T, U>>(std::declval<U>());
  246. };
  247. // } &&
  248. // CommonReference<
  249. // std::add_lvalue_reference_t<const T>,
  250. // std::add_lvalue_reference_t<const U>> &&
  251. // CommonReference<
  252. // std::add_lvalue_reference_t<std::common_type_t<T, U>>,
  253. // std::common_reference_t<
  254. // std::add_lvalue_reference_t<const T>,
  255. // std::add_lvalue_reference_t<const U>
  256. // >
  257. // >;
  258. #else
  259. // meta::and_ <
  260. Same<std::common_type_t<T, U>, std::common_type_t<U, T>>; //>
  261. // meta::bool_<CommonReference<
  262. // std::add_lvalue_reference_t<const T>,
  263. // std::add_lvalue_reference_t<const U>
  264. // >>,
  265. // meta::bool_< CommonReference<
  266. // std::add_lvalue_reference_t<std::common_type_t<T, U>>,
  267. // common_reference_t<
  268. // std::add_lvalue_reference_t<const T>,
  269. // std::add_lvalue_reference_t<const U>
  270. // >
  271. // >>
  272. // >::value;
  273. #endif
  274. /*!
  275. * Integral
  276. */
  277. template <class T>
  278. _utlConcept Integral = std::is_integral<T>::value;
  279. /*!
  280. * Signed Integral
  281. */
  282. template <class T>
  283. _utlConcept SignedIntegral = Integral<T> && std::is_signed<T>::value;
  284. /*!
  285. * Unsigned Integral
  286. */
  287. template <class T>
  288. _utlConcept UnsignedIntegral = Integral<T> && !std::is_signed<T>::value;
  289. template <typename T>
  290. _utlConcept MoveAssignable = std::is_move_assignable<T>::value;
  291. template <typename T>
  292. _utlConcept CopyAssignable = std::is_copy_assignable<T>::value;
  293. /*!
  294. * Assignable
  295. * \note != std:: on CommonReference
  296. */
  297. template<class LHS, class RHS>
  298. _utlConcept Assignable =
  299. #if CXX_CONCEPTS
  300. std::is_lvalue_reference<LHS>::value &&
  301. // CommonReference<
  302. // const std::remove_reference_t<L>&,
  303. // const std::remove_reference_t<R>&> &&
  304. requires(LHS lhs, RHS&& rhs) {
  305. lhs = std::forward<RHS>(rhs);
  306. requires Same<
  307. decltype(lhs = std::forward<RHS>(rhs)), LHS
  308. >;
  309. };
  310. #else
  311. std::is_assignable<LHS, RHS>::value;
  312. #endif
  313. /*!
  314. * Swappable, SwappableWith
  315. */
  316. //! @{
  317. #if CXX_VER < CXX_VER_STD_17
  318. namespace swappable_with_impl {
  319. struct is_swappable_with_ {
  320. // can apply std::swap
  321. template<typename _Tp,
  322. typename _Up,
  323. typename
  324. = decltype(std::swap(std::declval<_Tp&>(), std::declval<_Up&>())),
  325. typename
  326. = decltype(std::swap(std::declval<_Up&>(), std::declval<_Tp&>()))>
  327. static meta::true_ check(int);
  328. // can not apply std::swap
  329. template<typename, typename> static meta::false_ check(...);
  330. };
  331. }
  332. template <typename _Tp, typename _Up>
  333. struct is_swappable_with
  334. : swappable_with_impl::is_swappable_with_ {
  335. using type = decltype(check<_Tp, _Up>(0));
  336. };
  337. #else
  338. template<typename Tp>
  339. using is_swappable = std::is_swappable<Tp>;
  340. template<typename T, typename U>
  341. using is_swappable_with = std::is_swappable_with<T, U>;
  342. #endif
  343. // != std:: on CommonReference
  344. template<class T, class U>
  345. _utlConcept SwappableWith =
  346. is_swappable_with<T, T>::type::value &&
  347. is_swappable_with<U, U>::type::value &&
  348. is_swappable_with<T, U>::type::value &&
  349. is_swappable_with<U, T>::type::value;
  350. // std::CommonReference<
  351. // const std::remove_reference_t<T>&,
  352. // const std::remove_reference_t<U>&
  353. // >;
  354. // != std:: we use is_swappable_with now is_swappable
  355. template<class T>
  356. _utlConcept Swappable = is_swappable_with<T, T>::type::value;
  357. //! @}
  358. /*!
  359. * Destructible
  360. */
  361. template <class T>
  362. _utlConcept Destructible = std::is_nothrow_destructible<T>::value;
  363. /*!
  364. * Constructible
  365. */
  366. template <class T, class... Args>
  367. _utlConcept Constructible =
  368. Destructible<T> && std::is_constructible<T, Args...>::value;
  369. /*!
  370. * DefaultConstructible
  371. */
  372. template <class T>
  373. _utlConcept DefaultConstructible = Constructible<T>;
  374. /*!
  375. * MoveConstructible
  376. * \note
  377. * Another approach would be std::is_move_constructible<T>::value;
  378. */
  379. template<class T>
  380. _utlConcept MoveConstructible =
  381. Constructible<T, T> && ConvertibleTo<T, T>;
  382. /*!
  383. * CopyConstructible
  384. */
  385. template <class T>
  386. _utlConcept CopyConstructible =
  387. MoveConstructible<T> &&
  388. Constructible<T, _ref_t<T>> && ConvertibleTo<_ref_t<T>, T> &&
  389. Constructible<T, const _ref_t<T>> && ConvertibleTo<const _ref_t<T>, T> &&
  390. Constructible<T, const T> && ConvertibleTo<const T, T>;
  391. /*!
  392. * Movable
  393. */
  394. template <class T>
  395. _utlConcept Movable =
  396. std::is_object<T>::value &&
  397. MoveConstructible<T> &&
  398. Assignable<_ref_t<T>, T> &&
  399. Swappable<T>;
  400. /*!
  401. * Copyable
  402. */
  403. template <class T>
  404. _utlConcept Copyable =
  405. CopyConstructible<T> &&
  406. Movable<T> &&
  407. Assignable<_ref_t<T>, const _ref_t<T>>;
  408. /*!
  409. * Boolean
  410. */
  411. #if CXX_CONCEPTS
  412. template <class B>
  413. _utlConcept Boolean =
  414. Movable<remove_cvref_t<B>> &&
  415. requires(const std::remove_reference_t<B>& b1,
  416. const std::remove_reference_t<B>& b2, const bool a) {
  417. requires ConvertibleTo<const std::remove_reference_t<B>&, bool>;
  418. !b1; requires ConvertibleTo<decltype(!b1), bool>;
  419. b1 && a; requires Same<decltype(b1 && a), bool>;
  420. b1 || a; requires Same<decltype(b1 || a), bool>;
  421. b1 && b2; requires Same<decltype(b1 && b2), bool>;
  422. a && b2; requires Same<decltype(a && b2), bool>;
  423. b1 || b2; requires Same<decltype(b1 || b2), bool>;
  424. a || b2; requires Same<decltype(a || b2), bool>;
  425. b1 == b2; requires ConvertibleTo<decltype(b1 == b2), bool>;
  426. b1 == a; requires ConvertibleTo<decltype(b1 == a), bool>;
  427. a == b2; requires ConvertibleTo<decltype(a == b2), bool>;
  428. b1 != b2; requires ConvertibleTo<decltype(b1 != b2), bool>;
  429. b1 != a; requires ConvertibleTo<decltype(b1 != a), bool>;
  430. a != b2; requires ConvertibleTo<decltype(a != b2), bool>;
  431. };
  432. #else
  433. namespace details {
  434. // template <typename B> using try_op_not_ = decltype(!std::declval<cref_<B>>());
  435. // template <typename B> using try_op_eq_ = decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>());
  436. // template <typename B> using try_op_neq_ = decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>());
  437. // template <typename B> using try_op_and_ = decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>());
  438. // template <typename B> using try_op_or_ = decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>());
  439. //
  440. // template <typename B>
  441. // struct is_boolean__ {
  442. // using type = meta::and_ <
  443. // meta::is_detected<B, try_op_not_>,
  444. // meta::is_detected<B, try_op_eq_>,
  445. // meta::is_detected<B, try_op_neq_>,
  446. // meta::is_detected<B, try_op_and_>,
  447. // meta::is_detected<B, try_op_or_>
  448. // >;
  449. // };
  450. template <typename B, typename = void>
  451. struct is_boolean_ {
  452. using type = meta::false_;
  453. };
  454. template <typename B>
  455. struct is_boolean_ <B, meta::void_t<
  456. meta::use_if_same_t<bool, decltype(!std::declval<cref_<B>>())>,
  457. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>())>,
  458. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>())>,
  459. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>())>,
  460. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>())>
  461. >> {
  462. using type = meta::true_;
  463. };
  464. template <typename B>
  465. using is_boolean_t = meta::eval <
  466. is_boolean_<B>
  467. >;
  468. }
  469. template <class B>
  470. _utlConcept Boolean =
  471. Movable<remove_cvref_t<B>> &&
  472. //ConvertibleTo<const std::remove_reference_t<B>&, bool> &&
  473. ConvertibleTo<const _ref_t<B>, bool> &&
  474. Same<meta::true_, details::is_boolean_t<B>>;
  475. #endif
  476. namespace details {
  477. template <typename T, typename U, typename = void>
  478. struct is_weakly_equality_comparable_with_ {
  479. using type = meta::false_;
  480. };
  481. template <typename T, typename U>
  482. struct is_weakly_equality_comparable_with_<T, U, meta::void_t<
  483. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() == std::declval<cref_<U>>())>,
  484. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() != std::declval<cref_<U>>())>,
  485. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() == std::declval<cref_<T>>())>,
  486. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() != std::declval<cref_<T>>())>
  487. >> {
  488. using type = meta::true_;
  489. };
  490. template <typename T, typename U>
  491. using is_weakly_equality_comparable_with_t = meta::eval<
  492. is_weakly_equality_comparable_with_ <T, U>
  493. >;
  494. }
  495. template <class T, class U>
  496. _utlConcept WeaklyEqualityComparableWith =
  497. #if CXX_CONCEPTS
  498. requires(const std::remove_reference_t<T>& t,
  499. const std::remove_reference_t<U>& u) {
  500. t == u; requires Boolean<decltype(t == u)>;
  501. t != u; requires Boolean<decltype(t != u)>;
  502. u == t; requires Boolean<decltype(u == t)>;
  503. u != t; requires Boolean<decltype(u != t)>;
  504. };
  505. #else
  506. Same<meta::true_, details::is_weakly_equality_comparable_with_t<T, U>>;
  507. #endif
  508. template <class T>
  509. _utlConcept EqualityComparable = WeaklyEqualityComparableWith<T, T>;
  510. template <class T, class U>
  511. _utlConcept EqualityComparableWith =
  512. EqualityComparable<T> &&
  513. EqualityComparable<U> &&
  514. // CommonReference<
  515. // const std::remove_reference_t<T>&,
  516. // const std::remove_reference_t<U>&> &&
  517. // EqualityComparable<
  518. // common_reference_t<
  519. // const std::remove_reference_t<T>&,
  520. // const std::remove_reference_t<U>&>> &&
  521. WeaklyEqualityComparableWith<T, U>;
  522. #if CXX_CONCEPTS
  523. template <class T>
  524. _utlConcept StrictTotallyOrdered =
  525. EqualityComparable<T> &&
  526. requires(const std::remove_reference_t<T>& a,
  527. const std::remove_reference_t<T>& b) {
  528. a < b; requires Boolean<decltype(a < b)>;
  529. a > b; requires Boolean<decltype(a > b)>;
  530. a <= b; requires Boolean<decltype(a <= b)>;
  531. a >= b; requires Boolean<decltype(a >= b)>;
  532. };
  533. #else
  534. namespace details {
  535. template <typename T, typename = void>
  536. struct is_strict_totally_ordered_ {
  537. using type = meta::false_;
  538. };
  539. template <typename T>
  540. struct is_strict_totally_ordered_ <T, meta::void_t <
  541. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() < std::declval<cref_<T>>())>,
  542. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() > std::declval<cref_<T>>())>,
  543. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() <= std::declval<cref_<T>>())>,
  544. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() >= std::declval<cref_<T>>())>
  545. >> {
  546. using type = meta::true_;
  547. };
  548. template <typename T>
  549. using is_strict_totally_ordered_t = meta::eval <
  550. is_strict_totally_ordered_<T>
  551. >;
  552. }
  553. template <class T>
  554. _utlConcept StrictTotallyOrdered =
  555. EqualityComparable<T> &&
  556. Same <meta::true_, details::is_strict_totally_ordered_t<T>>;
  557. #endif
  558. #if CXX_CONCEPTS
  559. template <class T, class U>
  560. _utlConcept StrictTotallyOrderedWith =
  561. StrictTotallyOrdered<T> &&
  562. StrictTotallyOrdered<U> &&
  563. // CommonReference<
  564. // const std::remove_reference_t<T>&,
  565. // const std::remove_reference_t<U>&
  566. // > &&
  567. // StrictTotallyOrdered<
  568. // common_reference_t<
  569. // const std::remove_reference_t<T>&,
  570. // const std::remove_reference_t<U>&
  571. // >
  572. // > &&
  573. EqualityComparableWith<T, U> &&
  574. requires(const std::remove_reference_t<T>& t,
  575. const std::remove_reference_t<U>& u) {
  576. t < u; requires Boolean<decltype(t < u)>;
  577. t > u; requires Boolean<decltype(t > u)>;
  578. t <= u; requires Boolean<decltype(t <= u)>;
  579. t >= u; requires Boolean<decltype(t >= u)>;
  580. u < t; requires Boolean<decltype(u < t)>;
  581. u > t; requires Boolean<decltype(u > t)>;
  582. u <= t; requires Boolean<decltype(u <= t)>;
  583. u >= t; requires Boolean<decltype(u >= t)>;
  584. };
  585. #else
  586. namespace details {
  587. template <typename T, typename U, typename = void>
  588. struct is_strict_totally_ordered_with_ {
  589. using type = meta::false_;
  590. };
  591. template <typename T, typename U>
  592. struct is_strict_totally_ordered_with_ <T, U, meta::void_t <
  593. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() < std::declval<cref_<U>>())>,
  594. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() > std::declval<cref_<U>>())>,
  595. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() <= std::declval<cref_<U>>())>,
  596. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() >= std::declval<cref_<U>>())>,
  597. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() < std::declval<cref_<T>>())>,
  598. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() > std::declval<cref_<T>>())>,
  599. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() <= std::declval<cref_<T>>())>,
  600. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() >= std::declval<cref_<T>>())>
  601. >> {
  602. using type = meta::true_;
  603. };
  604. template <typename T, typename U>
  605. using is_strict_totally_ordered_with_t = meta::eval <
  606. is_strict_totally_ordered_with_<T, U>
  607. >;
  608. }
  609. template <class T, class U>
  610. _utlConcept StrictTotallyOrderedWith =
  611. StrictTotallyOrdered<T> &&
  612. StrictTotallyOrdered<U> &&
  613. EqualityComparableWith<T, U> &&
  614. Same <meta::true_, details::is_strict_totally_ordered_with_t<T, U>>;
  615. #endif
  616. /*!
  617. * Semiregular
  618. */
  619. template <class T>
  620. _utlConcept Semiregular = Copyable<T> && DefaultConstructible<T>;
  621. /*!
  622. * Regular
  623. */
  624. template <class T>
  625. _utlConcept Regular = Semiregular<T> && EqualityComparable<T>;
  626. /*!
  627. * Scalar
  628. */
  629. template<class T>
  630. _utlConcept Scalar =
  631. std::is_scalar<T>::value && Regular<T>;
  632. /*!
  633. * Arithmetic
  634. */
  635. template<class T>
  636. _utlConcept Arithmetic =
  637. std::is_arithmetic<T>::value && Scalar<T> && StrictTotallyOrdered<T>;
  638. /*!
  639. * FloatingPoint
  640. */
  641. template<class T>
  642. _utlConcept FloatingPoint =
  643. std::is_floating_point<T>::value && Arithmetic<T>;
  644. /*!
  645. * Invocable
  646. */
  647. template <class F, class... Args>
  648. _utlConcept Invocable = is_invocable<F, Args...>::value;
  649. // requires(F&& f, Args&&... args) {
  650. // invoke(std::forward<F>(f), std::forward<Args>(args)...);
  651. // };
  652. template< class F, class... Args >
  653. _utlConcept RegularInvocable = Invocable<F, Args...>;
  654. template < class F, class... Args >
  655. _utlConcept Predicate =
  656. RegularInvocable<F, Args...> &&
  657. Boolean<invoke_result_t<F, Args...>>;
  658. template <class R, class T, class U>
  659. _utlConcept Relation =
  660. Predicate<R, T, T> && Predicate<R, U, U> &&
  661. Predicate<R, T, U> && Predicate<R, U, T>;
  662. template < class R, class T, class U >
  663. _utlConcept StrictWeakOrder = Relation<R, T, U>;
  664. }
  665. //! @}
  666. #endif /* __utl_concepts_stl_h__ */