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.
 
 
 
 

752 lines
24 KiB

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