You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

718 lines
32KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_UTILITY_COMMON_TUPLE_HPP
  14. #define RANGES_V3_UTILITY_COMMON_TUPLE_HPP
  15. #include <utility>
  16. #include <meta/meta.hpp>
  17. #include <concepts/concepts.hpp>
  18. #include <range/v3/range_fwd.hpp>
  19. #include <range/v3/detail/adl_get.hpp>
  20. #include <range/v3/functional/bind.hpp>
  21. #include <range/v3/functional/reference_wrapper.hpp>
  22. #include <range/v3/utility/common_type.hpp>
  23. #include <range/v3/utility/tuple_algorithm.hpp>
  24. namespace ranges
  25. {
  26. /// \cond
  27. namespace detail
  28. {
  29. template<typename... Us, typename Tup, std::size_t... Is>
  30. std::tuple<Us...> to_std_tuple(Tup && tup, meta::index_sequence<Is...>)
  31. {
  32. return std::tuple<Us...>{adl_get<Is>(static_cast<Tup &&>(tup))...};
  33. }
  34. #ifdef RANGES_WORKAROUND_MSVC_786312
  35. template<std::size_t, typename...>
  36. struct args_;
  37. template<typename, typename>
  38. inline constexpr bool argstructible = false;
  39. template<std::size_t N, typename... Ts, typename... Us>
  40. inline constexpr bool argstructible<args_<N, Ts...>, args_<N, Us...>> =
  41. (META_IS_CONSTRUCTIBLE(Ts, Us) && ...);
  42. template<typename, typename>
  43. inline constexpr bool argsignable = false;
  44. template<std::size_t N, typename... Ts, typename... Us>
  45. inline constexpr bool argsignable<args_<N, Ts...>, args_<N, Us...>> =
  46. (std::is_assignable_v<Ts &, Us> && ...);
  47. #endif // RANGES_WORKAROUND_MSVC_786312
  48. template<std::size_t N, typename... Ts>
  49. struct args_
  50. {
  51. template<typename... Us>
  52. args_(args_<N, Us...>, meta::if_c<
  53. #ifdef RANGES_WORKAROUND_MSVC_786312
  54. argstructible<args_, args_<N, Us...>>
  55. #else // ^^^ workaround / no workaround vvv
  56. meta::and_c<META_IS_CONSTRUCTIBLE(Ts,
  57. Us)...>::value
  58. #endif // RANGES_WORKAROUND_MSVC_786312
  59. > * = nullptr)
  60. {}
  61. template<typename... Us>
  62. meta::if_c<
  63. #ifdef RANGES_WORKAROUND_MSVC_786312
  64. argsignable<args_, args_<N, Us...>>,
  65. #else // ^^^ workaround / no workaround vvv
  66. meta::and_c<std::is_assignable<Ts &, Us>::value...>::value,
  67. #endif // RANGES_WORKAROUND_MSVC_786312
  68. args_ &>
  69. operator=(args_<N, Us...>)
  70. {
  71. return *this;
  72. }
  73. };
  74. template<typename... Ts>
  75. using args = args_<sizeof...(Ts), Ts...>;
  76. template<typename... Ts>
  77. using rargs = args_<sizeof...(Ts), Ts &...>;
  78. } // namespace detail
  79. /// \endcond
  80. template<typename... Ts>
  81. struct common_tuple : _tuple_wrapper_::forward_tuple_interface<std::tuple<Ts...>>
  82. {
  83. private:
  84. template<typename That, std::size_t... Is>
  85. common_tuple(That && that, meta::index_sequence<Is...>)
  86. : common_tuple::forward_tuple_interface{
  87. detail::adl_get<Is>(static_cast<That &&>(that))...}
  88. {}
  89. struct element_assign_
  90. {
  91. template<typename T, typename U>
  92. int operator()(T & t, U && u) const
  93. {
  94. t = static_cast<U &&>(u);
  95. return 0;
  96. }
  97. };
  98. public:
  99. // Construction
  100. CPP_member
  101. CPP_ctor(common_tuple)()( //
  102. noexcept(meta::and_c<
  103. std::is_nothrow_default_constructible<Ts>::value...>::value) //
  104. requires default_constructible<std::tuple<Ts...>>)
  105. : common_tuple::forward_tuple_interface{}
  106. {}
  107. CPP_template(typename... Us)( //
  108. requires constructible_from<detail::args<Ts...>, detail::args<Us...>>) //
  109. explicit common_tuple(Us &&... us) noexcept(
  110. meta::and_c<std::is_nothrow_constructible<Ts, Us>::value...>::value)
  111. : common_tuple::forward_tuple_interface{static_cast<Us &&>(us)...}
  112. {}
  113. template<typename... Us>
  114. CPP_ctor(common_tuple)(std::tuple<Us...> & that)( //
  115. noexcept(
  116. meta::and_c<std::is_nothrow_constructible<Ts, Us &>::value...>::value) //
  117. requires constructible_from<detail::args<Ts...>, detail::rargs<Us...>>)
  118. : common_tuple(that, meta::make_index_sequence<sizeof...(Ts)>{})
  119. {}
  120. template<typename... Us>
  121. CPP_ctor(common_tuple)(std::tuple<Us...> const & that)( //
  122. noexcept(meta::and_c<
  123. std::is_nothrow_constructible<Ts, Us const &>::value...>::value) //
  124. requires constructible_from<detail::args<Ts...>, detail::rargs<Us const...>>)
  125. : common_tuple(that, meta::make_index_sequence<sizeof...(Ts)>{})
  126. {}
  127. template<typename... Us>
  128. CPP_ctor(common_tuple)(std::tuple<Us...> && that)( //
  129. noexcept(
  130. meta::and_c<std::is_nothrow_constructible<Ts, Us>::value...>::value) //
  131. requires constructible_from<detail::args<Ts...>, detail::args<Us...>>)
  132. : common_tuple(std::move(that), meta::make_index_sequence<sizeof...(Ts)>{})
  133. {}
  134. template<typename... Us>
  135. CPP_ctor(common_tuple)(common_tuple<Us...> & that)( //
  136. noexcept(
  137. meta::and_c<std::is_nothrow_constructible<Ts, Us &>::value...>::value) //
  138. requires constructible_from<detail::args<Ts...>, detail::rargs<Us...>>)
  139. : common_tuple(that, meta::make_index_sequence<sizeof...(Ts)>{})
  140. {}
  141. template<typename... Us>
  142. CPP_ctor(common_tuple)(common_tuple<Us...> const & that)( //
  143. noexcept(meta::and_c<
  144. std::is_nothrow_constructible<Ts, Us const &>::value...>::value) //
  145. requires constructible_from<detail::args<Ts...>, detail::rargs<Us const...>>)
  146. : common_tuple(that, meta::make_index_sequence<sizeof...(Ts)>{})
  147. {}
  148. template<typename... Us>
  149. CPP_ctor(common_tuple)(common_tuple<Us...> && that)( //
  150. noexcept(
  151. meta::and_c<std::is_nothrow_constructible<Ts, Us>::value...>::value) //
  152. requires constructible_from<detail::args<Ts...>, detail::args<Us...>>)
  153. : common_tuple(std::move(that), meta::make_index_sequence<sizeof...(Ts)>{})
  154. {}
  155. std::tuple<Ts...> & base() noexcept
  156. {
  157. return *this;
  158. }
  159. std::tuple<Ts...> const & base() const noexcept
  160. {
  161. return *this;
  162. }
  163. // Assignment
  164. template<typename... Us>
  165. auto operator=(std::tuple<Us...> & that) noexcept(
  166. meta::and_c<std::is_nothrow_assignable<Ts &, Us &>::value...>::value)
  167. -> CPP_ret(common_tuple &)( //
  168. requires assignable_from<detail::args<Ts...> &, detail::rargs<Us...>>)
  169. {
  170. (void)tuple_transform(base(), that, element_assign_{});
  171. return *this;
  172. }
  173. template<typename... Us>
  174. auto operator=(std::tuple<Us...> const & that) noexcept(
  175. meta::and_c<std::is_nothrow_assignable<Ts &, Us const &>::value...>::value)
  176. -> CPP_ret(common_tuple &)( //
  177. requires assignable_from<detail::args<Ts...> &,
  178. detail::rargs<Us const...>>)
  179. {
  180. (void)tuple_transform(base(), that, element_assign_{});
  181. return *this;
  182. }
  183. template<typename... Us>
  184. auto operator=(std::tuple<Us...> && that) noexcept(
  185. meta::and_c<std::is_nothrow_assignable<Ts &, Us>::value...>::value)
  186. -> CPP_ret(common_tuple &)( //
  187. requires assignable_from<detail::args<Ts...> &, detail::args<Us...>>)
  188. {
  189. (void)tuple_transform(base(), std::move(that), element_assign_{});
  190. return *this;
  191. }
  192. template<typename... Us>
  193. auto operator=(std::tuple<Us...> & that) const noexcept(
  194. meta::and_c<std::is_nothrow_assignable<Ts const &, Us &>::value...>::value)
  195. -> CPP_ret(common_tuple const &)( //
  196. requires assignable_from<detail::args<Ts const...> &,
  197. detail::rargs<Us...>>)
  198. {
  199. (void)tuple_transform(base(), that, element_assign_{});
  200. return *this;
  201. }
  202. template<typename... Us>
  203. auto operator=(std::tuple<Us...> const & that) const
  204. noexcept(meta::and_c<
  205. std::is_nothrow_assignable<Ts const &, Us const &>::value...>::value)
  206. -> CPP_ret(common_tuple const &)( //
  207. requires assignable_from<detail::args<Ts const...> &,
  208. detail::rargs<Us const...>>)
  209. {
  210. (void)tuple_transform(base(), that, element_assign_{});
  211. return *this;
  212. }
  213. template<typename... Us>
  214. auto operator=(std::tuple<Us...> && that) const noexcept(
  215. meta::and_c<std::is_nothrow_assignable<Ts const &, Us &&>::value...>::value)
  216. -> CPP_ret(common_tuple const &)( //
  217. requires assignable_from<detail::args<Ts const...> &,
  218. detail::args<Us...>>)
  219. {
  220. (void)tuple_transform(base(), std::move(that), element_assign_{});
  221. return *this;
  222. }
  223. // Conversion
  224. CPP_template(typename... Us)( //
  225. requires constructible_from<detail::args<Us...>, detail::rargs<Ts...>>) //
  226. operator std::tuple<Us...>() &
  227. noexcept(
  228. meta::and_c<std::is_nothrow_constructible<Us, Ts &>::value...>::value)
  229. {
  230. return detail::to_std_tuple<Us...>(
  231. *this, meta::make_index_sequence<sizeof...(Ts)>{});
  232. }
  233. CPP_template(typename... Us)( //
  234. requires constructible_from<detail::args<Us...>,
  235. detail::rargs<Ts const...>>) //
  236. operator std::tuple<Us...>() const & noexcept(
  237. meta::and_c<std::is_nothrow_constructible<Us, Ts const &>::value...>::value)
  238. {
  239. return detail::to_std_tuple<Us...>(
  240. *this, meta::make_index_sequence<sizeof...(Ts)>{});
  241. }
  242. CPP_template(typename... Us)( //
  243. requires constructible_from<detail::args<Us...>, detail::args<Ts...>>) //
  244. operator std::tuple<Us...>() &&
  245. noexcept(meta::and_c<std::is_nothrow_constructible<Us, Ts>::value...>::value)
  246. {
  247. return detail::to_std_tuple<Us...>(
  248. std::move(*this), meta::make_index_sequence<sizeof...(Ts)>{});
  249. }
  250. };
  251. // Logical operators
  252. #define LOGICAL_OP(OP, CONCEPT) \
  253. template<typename... Ts, typename... Us> \
  254. auto operator OP(common_tuple<Ts...> const & a, common_tuple<Us...> const & b) \
  255. ->CPP_ret(bool)(requires and_v<CONCEPT<Ts, Us>...>) \
  256. { \
  257. return a.base() OP b.base(); \
  258. } \
  259. template<typename... Ts, typename... Us> \
  260. auto operator OP(std::tuple<Ts...> const & a, common_tuple<Us...> const & b) \
  261. ->CPP_ret(bool)(requires and_v<CONCEPT<Ts, Us>...>) \
  262. { \
  263. return a OP b.base(); \
  264. } \
  265. template<typename... Ts, typename... Us> \
  266. auto operator OP(common_tuple<Ts...> const & a, std::tuple<Us...> const & b) \
  267. ->CPP_ret(bool)(requires and_v<CONCEPT<Ts, Us>...>) \
  268. { \
  269. return a.base() OP b; \
  270. } \
  271. /**/
  272. LOGICAL_OP(==, equality_comparable_with)
  273. LOGICAL_OP(!=, equality_comparable_with)
  274. LOGICAL_OP(<, totally_ordered_with)
  275. LOGICAL_OP(<=, totally_ordered_with)
  276. LOGICAL_OP(>, totally_ordered_with)
  277. LOGICAL_OP(>=, totally_ordered_with)
  278. #undef LOGICAL_OP
  279. struct make_common_tuple_fn
  280. {
  281. template<typename... Args>
  282. common_tuple<bind_element_t<Args>...> operator()(Args &&... args) const noexcept(
  283. meta::and_c<std::is_nothrow_constructible<
  284. bind_element_t<Args>, unwrap_reference_t<Args>>::value...>::value)
  285. {
  286. return common_tuple<bind_element_t<Args>...>{
  287. unwrap_reference(static_cast<Args &&>(args))...};
  288. }
  289. };
  290. /// \ingroup group-utility
  291. /// \sa `make_common_tuple_fn`
  292. RANGES_INLINE_VARIABLE(make_common_tuple_fn, make_common_tuple)
  293. template<typename F, typename S>
  294. struct common_pair : std::pair<F, S>
  295. {
  296. private:
  297. std::pair<F, S> const & base() const noexcept
  298. {
  299. return *this;
  300. }
  301. public:
  302. // Construction
  303. CPP_member
  304. CPP_ctor(common_pair)()( //
  305. noexcept(std::is_nothrow_default_constructible<F>::value &&
  306. std::is_nothrow_default_constructible<S>::value) //
  307. requires default_constructible<F> && default_constructible<S>)
  308. : std::pair<F, S>{}
  309. {}
  310. template<typename F2, typename S2>
  311. CPP_ctor(common_pair)(F2 && f2, S2 && s2)( //
  312. noexcept(std::is_nothrow_constructible<F, F2>::value &&
  313. std::is_nothrow_constructible<S, S2>::value) //
  314. requires constructible_from<F, F2> && constructible_from<S, S2>)
  315. : std::pair<F, S>{static_cast<F2 &&>(f2), static_cast<S2 &&>(s2)}
  316. {}
  317. template<typename F2, typename S2>
  318. CPP_ctor(common_pair)(std::pair<F2, S2> & that)( //
  319. noexcept(std::is_nothrow_constructible<F, F2 &>::value &&
  320. std::is_nothrow_constructible<S, S2 &>::value) //
  321. requires constructible_from<F, F2 &> && constructible_from<S, S2 &>)
  322. : std::pair<F, S>{that.first, that.second}
  323. {}
  324. template<typename F2, typename S2>
  325. CPP_ctor(common_pair)(std::pair<F2, S2> const & that)( //
  326. noexcept(std::is_nothrow_constructible<F, F2 const &>::value &&
  327. std::is_nothrow_constructible<S, S2 const &>::value) //
  328. requires constructible_from<F, F2 const &> &&
  329. constructible_from<S, S2 const &>)
  330. : std::pair<F, S>{that.first, that.second}
  331. {}
  332. template<typename F2, typename S2>
  333. CPP_ctor(common_pair)(std::pair<F2, S2> && that)( //
  334. noexcept(std::is_nothrow_constructible<F, F2>::value &&
  335. std::is_nothrow_constructible<S, S2>::value) //
  336. requires constructible_from<F, F2> && constructible_from<S, S2>)
  337. : std::pair<F, S>{std::forward<F2>(that.first), std::forward<S2>(that.second)}
  338. {}
  339. // Conversion
  340. CPP_template(typename F2, typename S2)( //
  341. requires constructible_from<F2, F &> && constructible_from<S2, S &>) //
  342. operator std::pair<F2, S2>() &
  343. noexcept(std::is_nothrow_constructible<F2, F &>::value &&
  344. std::is_nothrow_constructible<S2, S &>::value)
  345. {
  346. return {this->first, this->second};
  347. }
  348. CPP_template(typename F2, typename S2)( //
  349. requires constructible_from<F2, F const &> &&
  350. constructible_from<S2, S const &>) //
  351. operator std::pair<F2, S2>() const & noexcept(
  352. std::is_nothrow_constructible<F2, F const &>::value &&
  353. std::is_nothrow_constructible<S2, S const &>::value)
  354. {
  355. return {this->first, this->second};
  356. }
  357. CPP_template(typename F2, typename S2)( //
  358. requires constructible_from<F2, F> && constructible_from<S2, S>) //
  359. operator std::pair<F2, S2>() &&
  360. noexcept(std::is_nothrow_constructible<F2, F>::value &&
  361. std::is_nothrow_constructible<S2, S>::value)
  362. {
  363. return {std::forward<F>(this->first), std::forward<S>(this->second)};
  364. }
  365. // Assignment
  366. template<typename F2, typename S2>
  367. auto operator=(std::pair<F2, S2> & that) noexcept(
  368. std::is_nothrow_assignable<F &, F2 &>::value &&
  369. std::is_nothrow_assignable<S &, S2 &>::value)
  370. -> CPP_ret(common_pair &)( //
  371. requires assignable_from<F &, F2 &> && assignable_from<S &, S2 &>)
  372. {
  373. this->first = that.first;
  374. this->second = that.second;
  375. return *this;
  376. }
  377. template<typename F2, typename S2>
  378. auto operator=(std::pair<F2, S2> const & that) noexcept(
  379. std::is_nothrow_assignable<F &, F2 const &>::value &&
  380. std::is_nothrow_assignable<S &, S2 const &>::value)
  381. -> CPP_ret(common_pair &)( //
  382. requires assignable_from<F &, F2 const &> &&
  383. assignable_from<S &, S2 const &>)
  384. {
  385. this->first = that.first;
  386. this->second = that.second;
  387. return *this;
  388. }
  389. template<typename F2, typename S2>
  390. auto operator=(std::pair<F2, S2> && that) noexcept(
  391. std::is_nothrow_assignable<F &, F2>::value &&
  392. std::is_nothrow_assignable<S &, S2>::value) -> CPP_ret(common_pair &)( //
  393. requires assignable_from<F &, F2> && assignable_from<S &, S2>)
  394. {
  395. this->first = static_cast<F2 &&>(that.first);
  396. this->second = static_cast<S2 &&>(that.second);
  397. return *this;
  398. }
  399. template<typename F2, typename S2>
  400. auto operator=(std::pair<F2, S2> & that) const
  401. noexcept(std::is_nothrow_assignable<F const &, F2 &>::value &&
  402. std::is_nothrow_assignable<S const &, S2 &>::value)
  403. -> CPP_ret(common_pair const &)( //
  404. requires assignable_from<F const &, F2 &> &&
  405. assignable_from<S const &, S2 &>)
  406. {
  407. this->first = that.first;
  408. this->second = that.second;
  409. return *this;
  410. }
  411. template<typename F2, typename S2>
  412. auto operator=(std::pair<F2, S2> const & that) const
  413. noexcept(std::is_nothrow_assignable<F const &, F2 const &>::value &&
  414. std::is_nothrow_assignable<S const &, S2 const &>::value)
  415. -> CPP_ret(common_pair const &)( //
  416. requires assignable_from<F const &, F2 const &> &&
  417. assignable_from<S const &, S2 const &>)
  418. {
  419. this->first = that.first;
  420. this->second = that.second;
  421. return *this;
  422. }
  423. template<typename F2, typename S2>
  424. auto operator=(std::pair<F2, S2> && that) const noexcept(
  425. std::is_nothrow_assignable<F const &, F2 &&>::value &&
  426. std::is_nothrow_assignable<S const &, S2 &&>::value)
  427. -> CPP_ret(common_pair const &)( //
  428. requires assignable_from<F const &, F2> && assignable_from<S const &, S2>)
  429. {
  430. this->first = static_cast<F2 &&>(that.first);
  431. this->second = static_cast<S2 &&>(that.second);
  432. return *this;
  433. }
  434. };
  435. // Logical operators
  436. template<typename F1, typename S1, typename F2, typename S2>
  437. auto operator==(common_pair<F1, S1> const & a, common_pair<F2, S2> const & b)
  438. -> CPP_ret(bool)( //
  439. requires equality_comparable_with<F1, F2> && equality_comparable_with<S1, S2>)
  440. {
  441. return a.first == b.first && a.second == b.second;
  442. }
  443. template<typename F1, typename S1, typename F2, typename S2>
  444. auto operator==(common_pair<F1, S1> const & a, std::pair<F2, S2> const & b)
  445. -> CPP_ret(bool)( //
  446. requires equality_comparable_with<F1, F2> && equality_comparable_with<S1, S2>)
  447. {
  448. return a.first == b.first && a.second == b.second;
  449. }
  450. template<typename F1, typename S1, typename F2, typename S2>
  451. auto operator==(std::pair<F1, S1> const & a, common_pair<F2, S2> const & b)
  452. -> CPP_ret(bool)( //
  453. requires equality_comparable_with<F1, F2> && equality_comparable_with<S1, S2>)
  454. {
  455. return a.first == b.first && a.second == b.second;
  456. }
  457. template<typename F1, typename S1, typename F2, typename S2>
  458. auto operator<(common_pair<F1, S1> const & a, common_pair<F2, S2> const & b)
  459. -> CPP_ret(bool)( //
  460. requires totally_ordered_with<F1, F2> && totally_ordered_with<S1, S2>)
  461. {
  462. return a.first < b.first || (!(b.first < a.first) && a.second < b.second);
  463. }
  464. template<typename F1, typename S1, typename F2, typename S2>
  465. auto operator<(std::pair<F1, S1> const & a, common_pair<F2, S2> const & b)
  466. -> CPP_ret(bool)( //
  467. requires totally_ordered_with<F1, F2> && totally_ordered_with<S1, S2>)
  468. {
  469. return a.first < b.first || (!(b.first < a.first) && a.second < b.second);
  470. }
  471. template<typename F1, typename S1, typename F2, typename S2>
  472. auto operator<(common_pair<F1, S1> const & a, std::pair<F2, S2> const & b)
  473. -> CPP_ret(bool)( //
  474. requires totally_ordered_with<F1, F2> && totally_ordered_with<S1, S2>)
  475. {
  476. return a.first < b.first || (!(b.first < a.first) && a.second < b.second);
  477. }
  478. #define LOGICAL_OP(OP, CONCEPT, RET) \
  479. template<typename F1, typename S1, typename F2, typename S2> \
  480. auto operator OP(common_pair<F1, S1> const & a, common_pair<F2, S2> const & b) \
  481. ->CPP_ret(bool)(requires CONCEPT<F1, F2> && CONCEPT<S1, S2>) \
  482. { \
  483. return RET; \
  484. } \
  485. template<typename F1, typename S1, typename F2, typename S2> \
  486. auto operator OP(std::pair<F1, S1> const & a, common_pair<F2, S2> const & b) \
  487. ->CPP_ret(bool)(requires CONCEPT<F1, F2> && CONCEPT<S1, S2>) \
  488. { \
  489. return RET; \
  490. } \
  491. template<typename F1, typename S1, typename F2, typename S2> \
  492. auto operator OP(common_pair<F1, S1> const & a, std::pair<F2, S2> const & b) \
  493. ->CPP_ret(bool)(requires CONCEPT<F1, F2> && CONCEPT<S1, S2>) \
  494. { \
  495. return RET; \
  496. } \
  497. /**/
  498. LOGICAL_OP(!=, equality_comparable_with, !(a == b))
  499. LOGICAL_OP(<=, totally_ordered_with, !(b < a))
  500. LOGICAL_OP(>, totally_ordered_with, (b < a))
  501. LOGICAL_OP(>=, totally_ordered_with, !(a < b))
  502. #undef LOGICAL_OP
  503. struct make_common_pair_fn
  504. {
  505. template<typename First, typename Second, typename F = bind_element_t<First>,
  506. typename S = bind_element_t<Second>>
  507. common_pair<F, S> operator()(First && f, Second && s) const noexcept(
  508. std::is_nothrow_constructible<F, unwrap_reference_t<First>>::value &&
  509. std::is_nothrow_constructible<F, unwrap_reference_t<Second>>::value)
  510. {
  511. return {unwrap_reference(static_cast<First &&>(f)),
  512. unwrap_reference(static_cast<Second &&>(s))};
  513. }
  514. };
  515. /// \ingroup group-utility
  516. /// \sa `make_common_pair_fn`
  517. RANGES_INLINE_VARIABLE(make_common_pair_fn, make_common_pair)
  518. /// \cond
  519. namespace detail
  520. {
  521. template<typename, typename, typename, typename = void>
  522. struct common_type_tuple_like
  523. {};
  524. template<template<typename...> class T0, typename... Ts,
  525. template<typename...> class T1, typename... Us, typename TupleLike>
  526. struct common_type_tuple_like<T0<Ts...>, T1<Us...>, TupleLike,
  527. meta::if_c<sizeof...(Ts) == sizeof...(Us)>>
  528. : meta::lazy::let<
  529. meta::lazy::invoke<TupleLike, meta::lazy::_t<common_type<Ts, Us>>...>>
  530. {};
  531. template<typename T, typename U>
  532. using make_common_pair =
  533. meta::if_<meta::or_<std::is_reference<T>, std::is_reference<U>>,
  534. common_pair<T, U>, std::pair<T, U>>;
  535. template<typename... Ts>
  536. using make_common_tuple =
  537. meta::if_<meta::any_of<meta::list<Ts...>, meta::quote<std::is_reference>>,
  538. common_tuple<Ts...>, std::tuple<Ts...>>;
  539. template<typename, typename, typename, typename = void>
  540. struct common_ref_tuple_like
  541. {};
  542. template<template<typename...> class T0, typename... Ts,
  543. template<typename...> class T1, typename... Us, typename TupleLike>
  544. struct common_ref_tuple_like<T0<Ts...>, T1<Us...>, TupleLike,
  545. meta::if_c<sizeof...(Ts) == sizeof...(Us)>>
  546. : meta::lazy::let<meta::lazy::invoke<
  547. TupleLike, meta::lazy::_t<common_reference<Ts, Us>>...>>
  548. {};
  549. } // namespace detail
  550. /// \endcond
  551. } // namespace ranges
  552. /// \cond
  553. namespace concepts
  554. {
  555. // common_type for pairs
  556. template<typename F1, typename S1, typename F2, typename S2>
  557. struct common_type<std::pair<F1, S1>, ranges::common_pair<F2, S2>>
  558. : ranges::detail::common_type_tuple_like<
  559. std::pair<F1, S1>, ranges::common_pair<F2, S2>,
  560. meta::quote<ranges::detail::make_common_pair>>
  561. {};
  562. template<typename F1, typename S1, typename F2, typename S2>
  563. struct common_type<ranges::common_pair<F1, S1>, std::pair<F2, S2>>
  564. : ranges::detail::common_type_tuple_like<
  565. ranges::common_pair<F1, S1>, std::pair<F2, S2>,
  566. meta::quote<ranges::detail::make_common_pair>>
  567. {};
  568. template<typename F1, typename S1, typename F2, typename S2>
  569. struct common_type<ranges::common_pair<F1, S1>, ranges::common_pair<F2, S2>>
  570. : ranges::detail::common_type_tuple_like<ranges::common_pair<F1, S1>,
  571. ranges::common_pair<F2, S2>,
  572. meta::quote<ranges::common_pair>>
  573. {};
  574. // common_type for tuples
  575. template<typename... Ts, typename... Us>
  576. struct common_type<ranges::common_tuple<Ts...>, std::tuple<Us...>>
  577. : ranges::detail::common_type_tuple_like<
  578. ranges::common_tuple<Ts...>, std::tuple<Us...>,
  579. meta::quote<ranges::detail::make_common_tuple>>
  580. {};
  581. template<typename... Ts, typename... Us>
  582. struct common_type<std::tuple<Ts...>, ranges::common_tuple<Us...>>
  583. : ranges::detail::common_type_tuple_like<
  584. std::tuple<Ts...>, ranges::common_tuple<Us...>,
  585. meta::quote<ranges::detail::make_common_tuple>>
  586. {};
  587. template<typename... Ts, typename... Us>
  588. struct common_type<ranges::common_tuple<Ts...>, ranges::common_tuple<Us...>>
  589. : ranges::detail::common_type_tuple_like<ranges::common_tuple<Ts...>,
  590. ranges::common_tuple<Us...>,
  591. meta::quote<ranges::common_tuple>>
  592. {};
  593. // common reference for pairs
  594. template<typename F1, typename S1, typename F2, typename S2,
  595. template<typename> class Qual1, template<typename> class Qual2>
  596. struct basic_common_reference<ranges::common_pair<F1, S1>, std::pair<F2, S2>, Qual1,
  597. Qual2>
  598. : ranges::detail::common_ref_tuple_like<
  599. ranges::common_pair<Qual1<F1>, Qual1<S1>>, std::pair<Qual2<F2>, Qual2<S2>>,
  600. meta::quote<ranges::detail::make_common_pair>>
  601. {};
  602. template<typename F1, typename S1, typename F2, typename S2,
  603. template<typename> class Qual1, template<typename> class Qual2>
  604. struct basic_common_reference<std::pair<F1, S1>, ranges::common_pair<F2, S2>, Qual1,
  605. Qual2>
  606. : ranges::detail::common_ref_tuple_like<
  607. std::pair<Qual1<F1>, Qual1<S1>>, ranges::common_pair<Qual2<F2>, Qual2<S2>>,
  608. meta::quote<ranges::detail::make_common_pair>>
  609. {};
  610. template<typename F1, typename S1, typename F2, typename S2,
  611. template<typename> class Qual1, template<typename> class Qual2>
  612. struct basic_common_reference<ranges::common_pair<F1, S1>,
  613. ranges::common_pair<F2, S2>, Qual1, Qual2>
  614. : ranges::detail::common_ref_tuple_like<ranges::common_pair<Qual1<F1>, Qual1<S1>>,
  615. ranges::common_pair<Qual2<F2>, Qual2<S2>>,
  616. meta::quote<ranges::common_pair>>
  617. {};
  618. // common reference for tuples
  619. template<typename... Ts, typename... Us, template<typename> class Qual1,
  620. template<typename> class Qual2>
  621. struct basic_common_reference<ranges::common_tuple<Ts...>, std::tuple<Us...>, Qual1,
  622. Qual2>
  623. : ranges::detail::common_ref_tuple_like<
  624. ranges::common_tuple<Qual1<Ts>...>, std::tuple<Qual2<Us>...>,
  625. meta::quote<ranges::detail::make_common_tuple>>
  626. {};
  627. template<typename... Ts, typename... Us, template<typename> class Qual1,
  628. template<typename> class Qual2>
  629. struct basic_common_reference<std::tuple<Ts...>, ranges::common_tuple<Us...>, Qual1,
  630. Qual2>
  631. : ranges::detail::common_ref_tuple_like<
  632. std::tuple<Qual1<Ts>...>, ranges::common_tuple<Qual2<Us>...>,
  633. meta::quote<ranges::detail::make_common_tuple>>
  634. {};
  635. template<typename... Ts, typename... Us, template<typename> class Qual1,
  636. template<typename> class Qual2>
  637. struct basic_common_reference<ranges::common_tuple<Ts...>,
  638. ranges::common_tuple<Us...>, Qual1, Qual2>
  639. : ranges::detail::common_ref_tuple_like<ranges::common_tuple<Qual1<Ts>...>,
  640. ranges::common_tuple<Qual2<Us>...>,
  641. meta::quote<ranges::common_tuple>>
  642. {};
  643. } // namespace concepts
  644. /// \endcond
  645. RANGES_DIAGNOSTIC_PUSH
  646. RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
  647. namespace std
  648. {
  649. template<typename First, typename Second>
  650. struct tuple_size<::ranges::common_pair<First, Second>>
  651. : std::integral_constant<size_t, 2>
  652. {};
  653. template<typename First, typename Second>
  654. struct tuple_element<0, ::ranges::common_pair<First, Second>>
  655. {
  656. using type = First;
  657. };
  658. template<typename First, typename Second>
  659. struct tuple_element<1, ::ranges::common_pair<First, Second>>
  660. {
  661. using type = Second;
  662. };
  663. template<typename... Ts>
  664. struct tuple_size<::ranges::common_tuple<Ts...>>
  665. : std::integral_constant<size_t, sizeof...(Ts)>
  666. {};
  667. template<size_t N, typename... Ts>
  668. struct tuple_element<N, ::ranges::common_tuple<Ts...>>
  669. : tuple_element<N, tuple<Ts...>>
  670. {};
  671. } // namespace std
  672. RANGES_DIAGNOSTIC_POP
  673. #endif