Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

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