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.
 
 
 
 

763 lignes
24 KiB

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