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.
 
 
 
 

777 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. using is_swappable = std::is_swappable;
  355. using is_swappable_with = std::is_swappable_with;
  356. #endif
  357. // != std:: on CommonReference
  358. template<class T, class U>
  359. _utlConcept SwappableWith =
  360. is_swappable_with<T, T>::type::value &&
  361. is_swappable_with<U, U>::type::value &&
  362. is_swappable_with<T, U>::type::value &&
  363. is_swappable_with<U, T>::type::value;
  364. // std::CommonReference<
  365. // const std::remove_reference_t<T>&,
  366. // const std::remove_reference_t<U>&
  367. // >;
  368. // != std:: we use is_swappable_with now is_swappable
  369. template<class T>
  370. _utlConcept Swappable = is_swappable_with<T, T>::type::value;
  371. //! @}
  372. /*!
  373. * Destructible
  374. */
  375. template <class T>
  376. _utlConcept Destructible = std::is_nothrow_destructible<T>::value;
  377. /*!
  378. * Constructible
  379. */
  380. template <class T, class... Args>
  381. _utlConcept Constructible =
  382. Destructible<T> && std::is_constructible<T, Args...>::value;
  383. /*!
  384. * DefaultConstructible
  385. */
  386. template <class T>
  387. _utlConcept DefaultConstructible = Constructible<T>;
  388. /*!
  389. * MoveConstructible
  390. * \note
  391. * Another approach would be std::is_move_constructible<T>::value;
  392. */
  393. template<class T>
  394. _utlConcept MoveConstructible =
  395. Constructible<T, T> && ConvertibleTo<T, T>;
  396. /*!
  397. * CopyConstructible
  398. */
  399. template <class T>
  400. _utlConcept CopyConstructible =
  401. MoveConstructible<T> &&
  402. Constructible<T, _ref_t<T>> && ConvertibleTo<_ref_t<T>, T> &&
  403. Constructible<T, const _ref_t<T>> && ConvertibleTo<const _ref_t<T>, T> &&
  404. Constructible<T, const T> && ConvertibleTo<const T, T>;
  405. /*!
  406. * Movable
  407. */
  408. template <class T>
  409. _utlConcept Movable =
  410. std::is_object<T>::value &&
  411. MoveConstructible<T> &&
  412. Assignable<_ref_t<T>, T> &&
  413. Swappable<T>;
  414. /*!
  415. * Copyable
  416. */
  417. template <class T>
  418. _utlConcept Copyable =
  419. CopyConstructible<T> &&
  420. Movable<T> &&
  421. Assignable<_ref_t<T>, const _ref_t<T>>;
  422. /*!
  423. * Boolean
  424. */
  425. #if CXX_CONCEPTS
  426. template <class B>
  427. _utlConcept Boolean =
  428. Movable<remove_cvref_t<B>> &&
  429. requires(const std::remove_reference_t<B>& b1,
  430. const std::remove_reference_t<B>& b2, const bool a) {
  431. requires ConvertibleTo<const std::remove_reference_t<B>&, bool>;
  432. !b1; requires ConvertibleTo<decltype(!b1), bool>;
  433. b1 && a; requires Same<decltype(b1 && a), bool>;
  434. b1 || a; requires Same<decltype(b1 || a), bool>;
  435. b1 && b2; requires Same<decltype(b1 && b2), bool>;
  436. a && b2; requires Same<decltype(a && b2), bool>;
  437. b1 || b2; requires Same<decltype(b1 || b2), bool>;
  438. a || b2; requires Same<decltype(a || b2), bool>;
  439. b1 == b2; requires ConvertibleTo<decltype(b1 == b2), bool>;
  440. b1 == a; requires ConvertibleTo<decltype(b1 == a), bool>;
  441. a == b2; requires ConvertibleTo<decltype(a == b2), bool>;
  442. b1 != b2; requires ConvertibleTo<decltype(b1 != b2), bool>;
  443. b1 != a; requires ConvertibleTo<decltype(b1 != a), bool>;
  444. a != b2; requires ConvertibleTo<decltype(a != b2), bool>;
  445. };
  446. #else
  447. namespace details {
  448. // template <typename B> using try_op_not_ = decltype(!std::declval<cref_<B>>());
  449. // template <typename B> using try_op_eq_ = decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>());
  450. // template <typename B> using try_op_neq_ = decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>());
  451. // template <typename B> using try_op_and_ = decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>());
  452. // template <typename B> using try_op_or_ = decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>());
  453. //
  454. // template <typename B>
  455. // struct is_boolean__ {
  456. // using type = meta::and_ <
  457. // meta::is_detected<B, try_op_not_>,
  458. // meta::is_detected<B, try_op_eq_>,
  459. // meta::is_detected<B, try_op_neq_>,
  460. // meta::is_detected<B, try_op_and_>,
  461. // meta::is_detected<B, try_op_or_>
  462. // >;
  463. // };
  464. template <typename B, typename = void>
  465. struct is_boolean_ {
  466. using type = meta::false_;
  467. };
  468. template <typename B>
  469. struct is_boolean_ <B, meta::void_t<
  470. meta::use_if_same_t<bool, decltype(!std::declval<cref_<B>>())>,
  471. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>())>,
  472. meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() != 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. >> {
  476. using type = meta::true_;
  477. };
  478. template <typename B>
  479. using is_boolean_t = meta::eval <
  480. is_boolean_<B>
  481. >;
  482. }
  483. template <class B>
  484. _utlConcept Boolean =
  485. Movable<remove_cvref_t<B>> &&
  486. //ConvertibleTo<const std::remove_reference_t<B>&, bool> &&
  487. ConvertibleTo<const _ref_t<B>, bool> &&
  488. Same<meta::true_, details::is_boolean_t<B>>;
  489. #endif
  490. namespace details {
  491. template <typename T, typename U, typename = void>
  492. struct is_weakly_equality_comparable_with_ {
  493. using type = meta::false_;
  494. };
  495. template <typename T, typename U>
  496. struct is_weakly_equality_comparable_with_<T, U, meta::void_t<
  497. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() == std::declval<cref_<U>>())>,
  498. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() != std::declval<cref_<U>>())>,
  499. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() == std::declval<cref_<T>>())>,
  500. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() != std::declval<cref_<T>>())>
  501. >> {
  502. using type = meta::true_;
  503. };
  504. template <typename T, typename U>
  505. using is_weakly_equality_comparable_with_t = meta::eval<
  506. is_weakly_equality_comparable_with_ <T, U>
  507. >;
  508. }
  509. template <class T, class U>
  510. _utlConcept WeaklyEqualityComparableWith =
  511. #if CXX_CONCEPTS
  512. requires(const std::remove_reference_t<T>& t,
  513. const std::remove_reference_t<U>& u) {
  514. t == u; requires Boolean<decltype(t == u)>;
  515. t != u; requires Boolean<decltype(t != u)>;
  516. u == t; requires Boolean<decltype(u == t)>;
  517. u != t; requires Boolean<decltype(u != t)>;
  518. };
  519. #else
  520. Same<meta::true_, details::is_weakly_equality_comparable_with_t<T, U>>;
  521. #endif
  522. template <class T>
  523. _utlConcept EqualityComparable = WeaklyEqualityComparableWith<T, T>;
  524. template <class T, class U>
  525. _utlConcept EqualityComparableWith =
  526. EqualityComparable<T> &&
  527. EqualityComparable<U> &&
  528. // CommonReference<
  529. // const std::remove_reference_t<T>&,
  530. // const std::remove_reference_t<U>&> &&
  531. // EqualityComparable<
  532. // common_reference_t<
  533. // const std::remove_reference_t<T>&,
  534. // const std::remove_reference_t<U>&>> &&
  535. WeaklyEqualityComparableWith<T, U>;
  536. #if CXX_CONCEPTS
  537. template <class T>
  538. _utlConcept StrictTotallyOrdered =
  539. EqualityComparable<T> &&
  540. requires(const std::remove_reference_t<T>& a,
  541. const std::remove_reference_t<T>& b) {
  542. a < b; requires Boolean<decltype(a < b)>;
  543. a > b; requires Boolean<decltype(a > b)>;
  544. a <= b; requires Boolean<decltype(a <= b)>;
  545. a >= b; requires Boolean<decltype(a >= b)>;
  546. };
  547. #else
  548. namespace details {
  549. template <typename T, typename = void>
  550. struct is_strict_totally_ordered_ {
  551. using type = meta::false_;
  552. };
  553. template <typename T>
  554. struct is_strict_totally_ordered_ <T, meta::void_t <
  555. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() < std::declval<cref_<T>>())>,
  556. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() > std::declval<cref_<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. >> {
  560. using type = meta::true_;
  561. };
  562. template <typename T>
  563. using is_strict_totally_ordered_t = meta::eval <
  564. is_strict_totally_ordered_<T>
  565. >;
  566. }
  567. template <class T>
  568. _utlConcept StrictTotallyOrdered =
  569. EqualityComparable<T> &&
  570. Same <meta::true_, details::is_strict_totally_ordered_t<T>>;
  571. #endif
  572. #if CXX_CONCEPTS
  573. template <class T, class U>
  574. _utlConcept StrictTotallyOrderedWith =
  575. StrictTotallyOrdered<T> &&
  576. StrictTotallyOrdered<U> &&
  577. // CommonReference<
  578. // const std::remove_reference_t<T>&,
  579. // const std::remove_reference_t<U>&
  580. // > &&
  581. // StrictTotallyOrdered<
  582. // common_reference_t<
  583. // const std::remove_reference_t<T>&,
  584. // const std::remove_reference_t<U>&
  585. // >
  586. // > &&
  587. EqualityComparableWith<T, U> &&
  588. requires(const std::remove_reference_t<T>& t,
  589. const std::remove_reference_t<U>& u) {
  590. t < u; requires Boolean<decltype(t < u)>;
  591. t > u; requires Boolean<decltype(t > u)>;
  592. t <= u; requires Boolean<decltype(t <= u)>;
  593. t >= u; requires Boolean<decltype(t >= u)>;
  594. u < t; requires Boolean<decltype(u < t)>;
  595. u > t; requires Boolean<decltype(u > t)>;
  596. u <= t; requires Boolean<decltype(u <= t)>;
  597. u >= t; requires Boolean<decltype(u >= t)>;
  598. };
  599. #else
  600. namespace details {
  601. template <typename T, typename U, typename = void>
  602. struct is_strict_totally_ordered_with_ {
  603. using type = meta::false_;
  604. };
  605. template <typename T, typename U>
  606. struct is_strict_totally_ordered_with_ <T, U, meta::void_t <
  607. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() < std::declval<cref_<U>>())>,
  608. meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() > std::declval<cref_<U>>())>,
  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_<U>>() < std::declval<cref_<T>>())>,
  612. meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() > std::declval<cref_<T>>())>,
  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. >> {
  616. using type = meta::true_;
  617. };
  618. template <typename T, typename U>
  619. using is_strict_totally_ordered_with_t = meta::eval <
  620. is_strict_totally_ordered_with_<T, U>
  621. >;
  622. }
  623. template <class T, class U>
  624. _utlConcept StrictTotallyOrderedWith =
  625. StrictTotallyOrdered<T> &&
  626. StrictTotallyOrdered<U> &&
  627. EqualityComparableWith<T, U> &&
  628. Same <meta::true_, details::is_strict_totally_ordered_with_t<T, U>>;
  629. #endif
  630. /*!
  631. * Semiregular
  632. */
  633. template <class T>
  634. _utlConcept Semiregular = Copyable<T> && DefaultConstructible<T>;
  635. /*!
  636. * Regular
  637. */
  638. template <class T>
  639. _utlConcept Regular = Semiregular<T> && EqualityComparable<T>;
  640. /*!
  641. * Scalar
  642. */
  643. template<class T>
  644. _utlConcept Scalar =
  645. std::is_scalar<T>::value && Regular<T>;
  646. /*!
  647. * Arithmetic
  648. */
  649. template<class T>
  650. _utlConcept Arithmetic =
  651. std::is_arithmetic<T>::value && Scalar<T> && StrictTotallyOrdered<T>;
  652. /*!
  653. * FloatingPoint
  654. */
  655. template<class T>
  656. _utlConcept FloatingPoint =
  657. std::is_floating_point<T>::value && Arithmetic<T>;
  658. /*!
  659. * Invocable
  660. */
  661. template <class F, class... Args>
  662. _utlConcept Invocable = is_invocable<F, Args...>::value;
  663. // requires(F&& f, Args&&... args) {
  664. // invoke(std::forward<F>(f), std::forward<Args>(args)...);
  665. // };
  666. template< class F, class... Args >
  667. _utlConcept RegularInvocable = Invocable<F, Args...>;
  668. template < class F, class... Args >
  669. _utlConcept Predicate =
  670. RegularInvocable<F, Args...> &&
  671. Boolean<invoke_result_t<F, Args...>>;
  672. template <class R, class T, class U>
  673. _utlConcept Relation =
  674. Predicate<R, T, T> && Predicate<R, U, U> &&
  675. Predicate<R, T, U> && Predicate<R, U, T>;
  676. template < class R, class T, class U >
  677. _utlConcept StrictWeakOrder = Relation<R, T, U>;
  678. }
  679. //! @}
  680. #endif /* __utl_concepts_stl_h__ */