附录二:一个MiniMPL库

本节介绍了MPL库的一个小型重构。 目标是尽可能向后兼容MPL,同时仍然使用Hana引擎。 只有MPL的“算法”部分被实现为一个案例研究,但是应该可以实现MPL的许多(但不是全部)元函数。

向下滚动到主函数以查看测试。 测试正是MPL文档中的示例,它们被复制/粘贴过来了,然后尽可能少地修改以使用此重构版本。

  1. // Copyright Louis Dionne 2013-2016
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  4. #include <boost/hana.hpp>
  5. #include <boost/hana/ext/boost/mpl.hpp>
  6. #include <boost/hana/ext/std.hpp>
  7. #include <boost/mpl/lambda.hpp>
  8. #include <boost/mpl/placeholders.hpp>
  9. #include <boost/mpl/quote.hpp>
  10. #include <iostream>
  11. #include <type_traits>
  12. namespace hana = boost::hana;
  13. namespace mpl = boost::mpl;
  14. namespace hpl {
  15. //////////////////////////////////////////////////////////////////////////////
  16. // Utilities
  17. //////////////////////////////////////////////////////////////////////////////
  18. namespace detail {
  19. template <typename Pred>
  20. constexpr auto mpl_predicate = hana::integral(hana::metafunction_class<
  21. typename mpl::lambda<Pred>::type
  22. >);
  23. template <typename F>
  24. constexpr auto mpl_metafunction = hana::metafunction_class<
  25. typename mpl::lambda<F>::type
  26. >;
  27. }
  28. //////////////////////////////////////////////////////////////////////////////
  29. // integral_c
  30. //////////////////////////////////////////////////////////////////////////////
  31. template <typename T, T v>
  32. using integral_c = std::integral_constant<T, v>;
  33. template <int i>
  34. using int_ = integral_c<int, i>;
  35. template <long i>
  36. using long_ = integral_c<long, i>;
  37. template <bool b>
  38. using bool_ = integral_c<bool, b>;
  39. using true_ = bool_<true>;
  40. using false_ = bool_<false>;
  41. //////////////////////////////////////////////////////////////////////////////
  42. // Sequences, compile-time integers & al
  43. //
  44. // Differences with the MPL:
  45. // 1. `pair<...>::first` and `pair<...>::second` won't work;
  46. // use `first<pair<...>>` instead
  47. //////////////////////////////////////////////////////////////////////////////
  48. template <typename ...T>
  49. using vector = hana::tuple<hana::type<T>...>;
  50. template <typename T, T ...v>
  51. using vector_c = hana::tuple<hana::integral_constant<T, v>...>;
  52. template <typename T, T from, T to>
  53. using range_c = decltype(hana::range_c<T, from, to>);
  54. template <typename T, typename U>
  55. using pair = hana::pair<hana::type<T>, hana::type<U>>;
  56. template <typename P>
  57. struct first : decltype(+hana::first(P{})) { };
  58. template <typename P>
  59. struct second : decltype(+hana::second(P{})) { };
  60. //////////////////////////////////////////////////////////////////////////////
  61. // Miscellaneous metafunctions
  62. //////////////////////////////////////////////////////////////////////////////
  63. template <typename C1, typename C2>
  64. struct equal_to
  65. : bool_<C1::value == C2::value>
  66. { };
  67. template <typename C1, typename C2>
  68. struct less
  69. : bool_<(C1::value < C2::value)>
  70. { };
  71. template <typename C1, typename C2>
  72. struct greater
  73. : bool_<(C1::value > C2::value)>
  74. { };
  75. template <typename N>
  76. struct next
  77. : integral_c<typename N::value_type, N::value + 1>
  78. { };
  79. //////////////////////////////////////////////////////////////////////////////
  80. // Intrinsics
  81. //
  82. // Differences with the MPL:
  83. // 1. `at` does not work for associative sequences; use `find` instead.
  84. // 2. `begin`, `end`, `clear`, `erase`, `erase_key`, `insert`, `insert_range`,
  85. // `is_sequence`, `key_type`, `order`, `sequence_tag`, `value_type`: not implemented
  86. //////////////////////////////////////////////////////////////////////////////
  87. template <typename Sequence, typename N>
  88. struct at
  89. : decltype(hana::at(Sequence{}, N{}))
  90. { };
  91. template <typename Sequence, long n>
  92. using at_c = at<Sequence, long_<n>>;
  93. template <typename Sequence>
  94. struct back
  95. : decltype(+hana::back(Sequence{}))
  96. { };
  97. template <typename Sequence>
  98. struct empty
  99. : decltype(hana::is_empty(Sequence{}))
  100. { };
  101. template <typename Sequence>
  102. struct front
  103. : decltype(+hana::front(Sequence{}))
  104. { };
  105. template <typename Sequence>
  106. struct pop_back {
  107. using type = decltype(hana::drop_back(
  108. hana::to_tuple(Sequence{}), hana::size_c<1>
  109. ));
  110. };
  111. template <typename Sequence>
  112. struct pop_front {
  113. using type = decltype(hana::drop_front(Sequence{}));
  114. };
  115. template <typename Sequence, typename T>
  116. struct push_back {
  117. using type = decltype(hana::append(Sequence{}, hana::type_c<T>));
  118. };
  119. template <typename Sequence, typename T>
  120. struct push_front {
  121. using type = decltype(hana::prepend(Sequence{}, hana::type_c<T>));
  122. };
  123. template <typename Sequence>
  124. struct size
  125. : decltype(hana::length(Sequence{}))
  126. { };
  127. //////////////////////////////////////////////////////////////////////////////
  128. // Iteration algorithms
  129. //
  130. // Differences with the MPL:
  131. // 1. reverse_fold:
  132. // Does not take an optional additional ForwardOp argument.
  133. //
  134. // 2. iter_fold, reverse_iter_fold:
  135. // Not implemented because we don't use iterators
  136. //////////////////////////////////////////////////////////////////////////////
  137. template <typename Sequence, typename State, typename F>
  138. struct fold
  139. : decltype(hana::fold(
  140. Sequence{}, hana::type_c<State>, detail::mpl_metafunction<F>
  141. ))
  142. { };
  143. template <typename Sequence, typename State, typename F>
  144. struct reverse_fold
  145. : decltype(hana::reverse_fold(
  146. Sequence{}, hana::type_c<State>, detail::mpl_metafunction<F>
  147. ))
  148. { };
  149. template <typename Sequence, typename State, typename F>
  150. using accumulate = fold<Sequence, State, F>;
  151. //////////////////////////////////////////////////////////////////////////////
  152. // Query algorithms
  153. //
  154. // Differences with the MPL:
  155. // 1. find_if and find:
  156. // Instead of returning an iterator, they either have a nested `::type`
  157. // alias to the answer, or they have no nested `::type` at all, which
  158. // makes them SFINAE-friendly.
  159. //
  160. // 2. lower_bound, upper_bound:
  161. // Not implemented.
  162. //
  163. // 3. {min,max}_element:
  164. // Not returning an iterator, and also won't work on empty sequences.
  165. //////////////////////////////////////////////////////////////////////////////
  166. template <typename Sequence, typename Pred>
  167. struct find_if
  168. : decltype(hana::find_if(Sequence{}, detail::mpl_predicate<Pred>))
  169. { };
  170. template <typename Sequence, typename T>
  171. struct find
  172. : decltype(hana::find(Sequence{}, hana::type_c<T>))
  173. { };
  174. template <typename Sequence, typename T>
  175. struct contains
  176. : decltype(hana::contains(Sequence{}, hana::type_c<T>))
  177. { };
  178. template <typename Sequence, typename T>
  179. struct count
  180. : decltype(hana::count(Sequence{}, hana::type_c<T>))
  181. { };
  182. template <typename Sequence, typename Pred>
  183. struct count_if
  184. : decltype(hana::count_if(Sequence{}, detail::mpl_predicate<Pred>))
  185. { };
  186. template <typename Sequence, typename Pred = mpl::quote2<less>>
  187. struct min_element
  188. : decltype(hana::minimum(Sequence{}, detail::mpl_predicate<Pred>))
  189. { };
  190. template <typename Sequence, typename Pred = mpl::quote2<less>>
  191. struct max_element
  192. : decltype(hana::maximum(Sequence{}, detail::mpl_predicate<Pred>))
  193. { };
  194. template <typename S1, typename S2, typename Pred = mpl::quote2<std::is_same>>
  195. struct equal
  196. : decltype( // inefficient but whatever
  197. hana::length(S1{}) == hana::length(S2{}) &&
  198. hana::all(hana::zip_shortest_with(detail::mpl_predicate<Pred>,
  199. hana::to_tuple(S1{}),
  200. hana::to_tuple(S2{})))
  201. )
  202. { };
  203. //////////////////////////////////////////////////////////////////////////////
  204. // Transformation algorithms
  205. //
  206. // Differences from the MPL:
  207. // 1. The algorithms do not accept an optional inserter, and they always
  208. // return a `vector`.
  209. // 2. stable_partition: not implemented
  210. // 3. All the reverse_* algorithms are not implemented.
  211. //////////////////////////////////////////////////////////////////////////////
  212. template <typename Sequence>
  213. struct copy {
  214. using type = decltype(hana::to_tuple(Sequence{}));
  215. };
  216. template <typename Sequence, typename Pred>
  217. struct copy_if {
  218. using type = decltype(hana::filter(
  219. hana::to_tuple(Sequence{}),
  220. detail::mpl_predicate<Pred>
  221. ));
  222. };
  223. template <typename Sequence, typename Sequence_or_Op, typename = void>
  224. struct transform;
  225. template <typename Sequence, typename Op>
  226. struct transform<Sequence, Op> {
  227. using type = decltype(hana::transform(
  228. hana::to_tuple(Sequence{}), detail::mpl_metafunction<Op>
  229. ));
  230. };
  231. template <typename S1, typename S2, typename Op>
  232. struct transform {
  233. using type = decltype(hana::zip_with(
  234. detail::mpl_metafunction<Op>,
  235. hana::to_tuple(S1{}),
  236. hana::to_tuple(S2{})
  237. ));
  238. };
  239. template <typename Sequence, typename OldType, typename NewType>
  240. struct replace {
  241. using type = decltype(hana::replace(
  242. hana::to_tuple(Sequence{}),
  243. hana::type_c<OldType>,
  244. hana::type_c<NewType>
  245. ));
  246. };
  247. template <typename Sequence, typename Pred, typename NewType>
  248. struct replace_if {
  249. using type = decltype(hana::replace_if(
  250. hana::to_tuple(Sequence{}),
  251. detail::mpl_predicate<Pred>,
  252. hana::type_c<NewType>
  253. ));
  254. };
  255. template <typename Sequence, typename T>
  256. struct remove {
  257. using type = decltype(hana::filter(
  258. hana::to_tuple(Sequence{}),
  259. hana::not_equal.to(hana::type_c<T>)
  260. ));
  261. };
  262. template <typename Sequence, typename Pred>
  263. struct remove_if {
  264. using type = decltype(hana::filter(
  265. hana::to_tuple(Sequence{}),
  266. hana::compose(hana::not_, detail::mpl_predicate<Pred>)
  267. ));
  268. };
  269. template <typename Sequence, typename Pred>
  270. struct unique {
  271. using type = decltype(hana::unique(
  272. hana::to_tuple(Sequence{}),
  273. detail::mpl_predicate<Pred>
  274. ));
  275. };
  276. template <typename Sequence, typename Pred>
  277. struct partition {
  278. using hana_pair = decltype(hana::partition(
  279. hana::to_tuple(Sequence{}),
  280. detail::mpl_predicate<Pred>
  281. ));
  282. using type = pair<
  283. decltype(hana::first(hana_pair{})),
  284. decltype(hana::second(hana_pair{}))
  285. >;
  286. };
  287. template <typename Sequence, typename Pred = mpl::quote2<less>>
  288. struct sort {
  289. using type = decltype(hana::sort(
  290. hana::to_tuple(Sequence{}), detail::mpl_predicate<Pred>
  291. ));
  292. };
  293. template <typename Sequence>
  294. struct reverse {
  295. using type = decltype(hana::reverse(hana::to_tuple(Sequence{})));
  296. };
  297. //////////////////////////////////////////////////////////////////////////////
  298. // Runtime algorithms
  299. //////////////////////////////////////////////////////////////////////////////
  300. template <typename Sequence, typename F>
  301. void for_each(F f) {
  302. hana::for_each(Sequence{}, [&f](auto t) {
  303. f(typename decltype(t)::type{});
  304. });
  305. }
  306. template <typename Sequence, typename TransformOp, typename F>
  307. void for_each(F f) {
  308. for_each<typename transform<Sequence, TransformOp>::type>(f);
  309. }
  310. } // end namespace hpl
  311. template <typename N>
  312. struct is_odd
  313. : hpl::bool_<(N::value % 2)>
  314. { };
  315. int main() {
  316. using namespace hpl;
  317. //////////////////////////////////////////////////////////////////////////////
  318. // Misc
  319. //////////////////////////////////////////////////////////////////////////////
  320. // pair
  321. {
  322. static_assert(std::is_same<first<pair<int, float>>::type, int>{}, "");
  323. static_assert(std::is_same<second<pair<int, float>>::type, float>{}, "");
  324. }
  325. //////////////////////////////////////////////////////////////////////////////
  326. // Intrinsics
  327. //////////////////////////////////////////////////////////////////////////////
  328. // at
  329. {
  330. using range = range_c<long,10,50>;
  331. static_assert(at<range, int_<0>>::value == 10, "");
  332. static_assert(at<range, int_<10>>::value == 20, "");
  333. static_assert(at<range, int_<40>>::value == 50, "");
  334. }
  335. // at_c
  336. {
  337. using range = range_c<long, 10, 50>;
  338. static_assert(at_c<range, 0>::value == 10, "");
  339. static_assert(at_c<range, 10>::value == 20, "");
  340. static_assert(at_c<range, 40>::value == 50, "");
  341. }
  342. // back
  343. {
  344. using range1 = range_c<int,0,1>;
  345. using range2 = range_c<int,0,10>;
  346. using range3 = range_c<int,-10,0>;
  347. using types = vector<int, char, float>;
  348. static_assert(back<range1>::value == 0, "");
  349. static_assert(back<range2>::value == 9, "");
  350. static_assert(back<range3>::value == -1, "");
  351. static_assert(std::is_same<back<types>::type, float>{}, "");
  352. }
  353. // empty
  354. {
  355. using empty_range = range_c<int,0,0>;
  356. using types = vector<long,float,double>;
  357. static_assert(empty<empty_range>{}, "");
  358. static_assert(!empty<types>{}, "");
  359. }
  360. // front
  361. {
  362. using types1 = vector<long>;
  363. using types2 = vector<int,long>;
  364. using types3 = vector<char,int,long>;
  365. static_assert(std::is_same<front<types1>::type, long>{}, "");
  366. static_assert(std::is_same<front<types2>::type, int>{}, "");
  367. static_assert(std::is_same<front<types3>::type, char>{}, "");
  368. }
  369. // pop_back
  370. {
  371. using types1 = vector<long>;
  372. using types2 = vector<long,int>;
  373. using types3 = vector<long,int,char>;
  374. using result1 = pop_back<types1>::type;
  375. using result2 = pop_back<types2>::type;
  376. using result3 = pop_back<types3>::type;
  377. static_assert(size<result1>::value == 0, "");
  378. static_assert(size<result2>::value == 1, "");
  379. static_assert(size<result3>::value == 2, "");
  380. static_assert(std::is_same< back<result2>::type, long>{}, "");
  381. static_assert(std::is_same< back<result3>::type, int>{}, "");
  382. }
  383. // pop_front
  384. {
  385. using types1 = vector<long>;
  386. using types2 = vector<int,long>;
  387. using types3 = vector<char,int,long>;
  388. using result1 = pop_front<types1>::type;
  389. using result2 = pop_front<types2>::type;
  390. using result3 = pop_front<types3>::type;
  391. static_assert(size<result1>::value == 0, "");
  392. static_assert(size<result2>::value == 1, "");
  393. static_assert(size<result3>::value == 2, "");
  394. static_assert(std::is_same<front<result2>::type, long>{}, "");
  395. static_assert(std::is_same<front<result3>::type, int>{}, "");
  396. }
  397. // push_back
  398. {
  399. using bools = vector_c<bool,false,false,false,true,true,true,false,false>;
  400. using message = push_back<bools, false_>::type;
  401. static_assert(back<message>::type::value == false, "");
  402. static_assert(count_if<message, equal_to<mpl::_1, false_>>{} == 6u, "");
  403. }
  404. // push_front
  405. {
  406. using v = vector_c<int,1,2,3,5,8,13,21>;
  407. static_assert(size<v>{} == 7u, "");
  408. using fibonacci = push_front<v, int_<1>>::type;
  409. static_assert(size<fibonacci>{} == 8u, "");
  410. static_assert(equal<
  411. fibonacci,
  412. vector_c<int,1,1,2,3,5,8,13,21>,
  413. equal_to<mpl::_, mpl::_>
  414. >{}, "");
  415. }
  416. // size
  417. {
  418. using empty_list = vector<>;
  419. using numbers = vector_c<int,0,1,2,3,4,5>;
  420. using more_numbers = range_c<int,0,100>;
  421. static_assert(size<empty_list>{} == 0u, "");
  422. static_assert(size<numbers>{} == 6u, "");
  423. static_assert(size<more_numbers>{} == 100u, "");
  424. }
  425. //////////////////////////////////////////////////////////////////////////////
  426. // Iteration algorithms
  427. //////////////////////////////////////////////////////////////////////////////
  428. // fold
  429. {
  430. using types = vector<long,float,short,double,float,long,long double>;
  431. using number_of_floats = fold<types, int_<0>,
  432. mpl::if_<std::is_floating_point<mpl::_2>,
  433. next<mpl::_1>,
  434. mpl::_1
  435. >
  436. >::type;
  437. static_assert(number_of_floats{} == 4, "");
  438. }
  439. // reverse_fold
  440. {
  441. using numbers = vector_c<int,5,-1,0,-7,-2,0,-5,4>;
  442. using negatives = vector_c<int,-1,-7,-2,-5>;
  443. using result = reverse_fold<numbers, vector_c<int>,
  444. mpl::if_<less<mpl::_2, int_<0>>,
  445. push_front<mpl::_1, mpl::_2>,
  446. mpl::_1
  447. >
  448. >::type;
  449. static_assert(equal<negatives, result>{}, "");
  450. }
  451. //////////////////////////////////////////////////////////////////////////////
  452. // Query algorithms
  453. //////////////////////////////////////////////////////////////////////////////
  454. // find_if
  455. {
  456. using types = vector<char,int,unsigned,long,unsigned long>;
  457. using found = find_if<types, std::is_same<mpl::_1, unsigned>>::type;
  458. static_assert(std::is_same<found, unsigned>{}, "");
  459. }
  460. // find
  461. {
  462. using types = vector<char,int,unsigned,long,unsigned long>;
  463. static_assert(std::is_same<find<types, unsigned>::type, unsigned>{}, "");
  464. }
  465. // contains
  466. {
  467. using types = vector<char,int,unsigned,long,unsigned long>;
  468. static_assert(!contains<types, bool>{}, "");
  469. }
  470. // count
  471. {
  472. using types = vector<int,char,long,short,char,short,double,long>;
  473. static_assert(count<types, short>{} == 2u, "");
  474. }
  475. // count_if
  476. {
  477. using types = vector<int,char,long,short,char,long,double,long>;
  478. static_assert(count_if<types, std::is_floating_point<mpl::_>>{} == 1u, "");
  479. static_assert(count_if<types, std::is_same<mpl::_, char>>{} == 2u, "");
  480. static_assert(count_if<types, std::is_same<mpl::_, void>>{} == 0u, "");
  481. }
  482. // min_element (MPL's example is completely broken)
  483. {
  484. }
  485. // max_element (MPL's example is completely broken)
  486. {
  487. }
  488. // equal
  489. {
  490. using s1 = vector<char,int,unsigned,long,unsigned long>;
  491. using s2 = vector<char,int,unsigned,long>;
  492. static_assert(!equal<s1,s2>{}, "");
  493. }
  494. //////////////////////////////////////////////////////////////////////////////
  495. // Transformaton algorithms
  496. //////////////////////////////////////////////////////////////////////////////
  497. // copy
  498. {
  499. using numbers = vector_c<int,10, 11, 12, 13, 14, 15, 16, 17, 18, 19>;
  500. using result = copy<range_c<int, 10, 20>>::type;
  501. static_assert(size<result>{} == 10u, "");
  502. static_assert(equal<result, numbers, mpl::quote2<equal_to>>{}, "");
  503. }
  504. // copy_if
  505. {
  506. using result = copy_if<range_c<int, 0, 10>, less<mpl::_1, int_<5>>>::type;
  507. static_assert(size<result>{} == 5u, "");
  508. static_assert(equal<result, range_c<int, 0, 5>>{}, "");
  509. }
  510. // transform
  511. {
  512. using types = vector<char,short,int,long,float,double>;
  513. using pointers = vector<char*,short*,int*,long*,float*,double*>;
  514. using result = transform<types,std::add_pointer<mpl::_1>>::type;
  515. static_assert(equal<result, pointers>{}, "");
  516. }
  517. // replace
  518. {
  519. using types = vector<int,float,char,float,float,double>;
  520. using expected = vector<int,double,char,double,double,double>;
  521. using result = replace< types,float,double >::type;
  522. static_assert(equal<result, expected>{}, "");
  523. }
  524. // replace_if
  525. {
  526. using numbers = vector_c<int,1,4,5,2,7,5,3,5>;
  527. using expected = vector_c<int,1,4,0,2,0,0,3,0>;
  528. using result = replace_if<numbers, greater<mpl::_, int_<4>>, int_<0>>::type;
  529. static_assert(equal<result, expected, mpl::quote2<equal_to>>{}, "");
  530. }
  531. // remove
  532. {
  533. using types = vector<int,float,char,float,float,double>;
  534. using result = hpl::remove<types, float>::type;
  535. static_assert(equal<result, vector<int, char, double>>{}, "");
  536. }
  537. // remove_if
  538. {
  539. using numbers = vector_c<int,1,4,5,2,7,5,3,5>;
  540. using result = remove_if<numbers, greater<mpl::_, int_<4> > >::type;
  541. static_assert(equal<result, vector_c<int,1,4,2,3>, mpl::quote2<equal_to>>{}, "");
  542. }
  543. // unique
  544. {
  545. using types = vector<int,float,float,char,int,int,int,double>;
  546. using expected = vector<int,float,char,int,double>;
  547. using result = unique<types, std::is_same<mpl::_1, mpl::_2>>::type;
  548. static_assert(equal<result, expected>{}, "");
  549. }
  550. // partition
  551. {
  552. using r = partition<range_c<int,0,10>, is_odd<mpl::_1>>::type;
  553. static_assert(equal<first<r>::type, vector_c<int,1,3,5,7,9>>{}, "");
  554. static_assert(equal<second<r>::type, vector_c<int,0,2,4,6,8>>{}, "");
  555. }
  556. // sort
  557. {
  558. using numbers = vector_c<int,3,4,0,-5,8,-1,7>;
  559. using expected = vector_c<int,-5,-1,0,3,4,7,8>;
  560. using result = sort<numbers>::type;
  561. static_assert(equal<result, expected, equal_to<mpl::_, mpl::_>>{}, "");
  562. }
  563. // reverse
  564. {
  565. using numbers = vector_c<int,9,8,7,6,5,4,3,2,1,0>;
  566. using result = reverse<numbers>::type;
  567. static_assert(equal<result, range_c<int,0,10>>{}, "");
  568. }
  569. //////////////////////////////////////////////////////////////////////////////
  570. // Runtime algorithms
  571. //////////////////////////////////////////////////////////////////////////////
  572. // for_each
  573. {
  574. auto value_printer = [](auto x) {
  575. std::cout << x << '\n';
  576. };
  577. for_each<range_c<int, 0, 10> >(value_printer);
  578. }
  579. }