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.
 
 
 
 

752 lignes
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__ */