meta.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /// \file meta.cpp Tests for Meta: a tiny metaprogramming library
  2. // Meta: a tiny metaprogramming 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. // Acknowledgements: Thanks for Paul Fultz for the suggestions that
  12. // concepts can be ordinary Boolean metafunctions.
  13. //
  14. // Project home: https://github.com/ericniebler/range-v3
  15. //
  16. #include <tuple>
  17. #include <meta/meta.hpp>
  18. #include "../simple_test.hpp"
  19. using namespace meta;
  20. // An implementation of tuple_cat gives Range v3's meta-programming and list
  21. // utilities a good workout. It's a good compiler stress test, too.
  22. namespace tc_detail
  23. {
  24. template<typename Ret, typename... Is, typename... Ks, typename Tuples>
  25. Ret tuple_cat_(list<Is...>, list<Ks...>, Tuples tpls)
  26. {
  27. return Ret{std::get<Ks::value>(std::get<Is::value>(tpls))...};
  28. }
  29. }
  30. template<typename... Tuples,
  31. typename Res = apply<quote<std::tuple>, concat<as_list<Tuples>...>>>
  32. Res tuple_cat(Tuples &&... tpls)
  33. {
  34. static constexpr std::size_t N = sizeof...(Tuples);
  35. // E.g. [0,0,0,2,2,2,3,3]
  36. using inner = join<
  37. transform<list<as_list<Tuples>...>,
  38. transform<as_list<make_index_sequence<N>>, quote<id>>, quote<transform>>>;
  39. // E.g. [0,1,2,0,1,2,0,1]
  40. using outer = join<
  41. transform<list<as_list<Tuples>...>,
  42. compose<quote<as_list>, quote_i<std::size_t, make_index_sequence>, quote<size>>>>;
  43. return tc_detail::tuple_cat_<Res>(inner{}, outer{},
  44. std::forward_as_tuple(std::forward<Tuples>(tpls)...));
  45. }
  46. void test_tuple_cat()
  47. {
  48. std::tuple<int, short, long> t1;
  49. std::tuple<> t2;
  50. std::tuple<float, double, long double> t3;
  51. std::tuple<void *, char *> t4;
  52. auto x = ::tuple_cat(t1, t2, t3, t4);
  53. using expected_type = std::tuple<int, short, long, float, double, long double, void *, char *>;
  54. static_assert(std::is_same<decltype(x), expected_type>::value, "");
  55. }
  56. // Other misc tests
  57. static_assert(std::is_same<reverse<list<int, short, double>>, list<double, short, int>>::value, "");
  58. static_assert(std::is_same<reverse<list<int, short, double, float>>, list<float, double, short, int>>::value, "");
  59. static_assert(std::is_same<reverse<list<int[1], int[2], int[3], int[4], int[5], int[6], int[7], int[8], int[9], int[10], int[11], int[12], int[13], int[14], int[15], int[16], int[17]>>, list<int[17], int[16], int[15], int[14], int[13], int[12], int[11], int[10], int[9], int[8], int[7], int[6], int[5], int[4], int[3], int[2], int[1]>>::value, "");
  60. static_assert(all_of<list<int, short, long>, quote<std::is_integral>>::value, "");
  61. static_assert(none_of<list<int, short, long>, quote<std::is_floating_point>>::value, "");
  62. static_assert(!any_of<list<int, short, long>, quote<std::is_floating_point>>::value, "");
  63. static_assert(any_of<list<int, short, long, float>, quote<std::is_floating_point>>::value, "");
  64. static_assert(std::is_same<invoke<uncurry<curry<quote_trait<id>>>, std::tuple<int, short, double>>,
  65. list<int, short, double>>::value,
  66. "");
  67. template<typename, typename, typename = void>
  68. struct can_invoke_ : std::false_type
  69. {
  70. };
  71. template<typename F, typename... As>
  72. struct can_invoke_<F, meta::list<As...>, meta::void_<meta::invoke<F, As...>>> : std::true_type
  73. {
  74. };
  75. template<typename F, typename... As>
  76. struct can_invoke : can_invoke_<F, meta::list<As...>>
  77. {
  78. };
  79. static_assert(can_invoke<meta::quote<std::pair>, int, int>::value, "");
  80. // I'm guessing this failure is due to GCC #64970
  81. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64970
  82. #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5
  83. static_assert(!can_invoke<meta::quote<std::pair>, int, int, int>::value, "");
  84. #endif
  85. // Sanity-check meta::lambda
  86. using Lambda0 = lambda<_a, _b, std::pair<_a, _b>>;
  87. using Lambda1 = lambda<_a, _b, std::pair<_b, _a>>;
  88. using Lambda2 = lambda<_a, _b, std::pair<_b, std::pair<_a, _a>>>;
  89. using Pair0 = invoke<Lambda0, int, short>;
  90. using Pair1 = invoke<Lambda1, int, short>;
  91. using Pair2 = invoke<Lambda2, int, short>;
  92. static_assert(std::is_same<Pair0, std::pair<int, short>>::value, "");
  93. static_assert(std::is_same<Pair1, std::pair<short, int>>::value, "");
  94. static_assert(std::is_same<Pair2, std::pair<short, std::pair<int, int>>>::value, "");
  95. // Not saying you should do it this way, but it's a good test.
  96. namespace l = meta::lazy;
  97. template<class L>
  98. using cart_prod = reverse_fold<
  99. L, list<list<>>,
  100. lambda<
  101. _a, _b,
  102. l::join<l::transform<
  103. _b, lambda<_c, l::join<l::transform<_a, lambda<_d, list<l::push_front<_d, _c>>>>>>>>>>;
  104. using CartProd = cart_prod<meta::list<meta::list<int, short>, meta::list<float, double>>>;
  105. static_assert(
  106. std::is_same<CartProd, meta::list<meta::list<int, float>, meta::list<int, double>,
  107. meta::list<short, float>, meta::list<short, double>>>::value,
  108. "");
  109. static_assert(can_invoke<lambda<_a, lazy::if_<std::is_integral<_a>, _a>>, int>::value, "");
  110. // I'm guessing this failure is due to GCC #64970
  111. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64970
  112. #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5
  113. static_assert(!can_invoke<lambda<_a, lazy::if_<std::is_integral<_a>, _a>>, float>::value, "");
  114. #endif
  115. template<typename List>
  116. using rev = reverse_fold<List, list<>, lambda<_a, _b, defer<push_back, _a, _b>>>;
  117. static_assert(std::is_same<rev<list<int, short, double>>, list<double, short, int>>::value, "");
  118. using uncvref_fn = lambda<_a, l::_t<std::remove_cv<l::_t<std::remove_reference<_a>>>>>;
  119. static_assert(std::is_same<invoke<uncvref_fn, int const &>, int>::value, "");
  120. using L = list<int, short, int, float>;
  121. static_assert(std::is_same<find<L, int>, list<int, short, int, float>>::value, "");
  122. static_assert(std::is_same<find_if<L, bind_front<quote<std::is_same>, int>>, list<int, short, int, float>>::value, "");
  123. static_assert(std::is_same<find_if<L, bind_front<quote<std::is_same>, double>>, list<>>::value, "");
  124. static_assert(std::is_same<reverse_find<L, int>, list<int, float>>::value, "");
  125. static_assert(std::is_same<reverse_find_if<L, bind_front<quote<std::is_same>, int>>, list<int, float>>::value, "");
  126. static_assert(std::is_same<reverse_find_if<L, bind_front<quote<std::is_same>, double>>, list<>>::value, "");
  127. struct check_integral
  128. {
  129. template<class T>
  130. constexpr T operator()(T &&i) const
  131. {
  132. static_assert(std::is_integral<T>{}, "");
  133. return i;
  134. }
  135. };
  136. // Test for meta::let
  137. template<typename T, typename List>
  138. using find_index_ = let<
  139. var<_a, List>, var<_b, lazy::find<_a, T>>,
  140. lazy::if_<std::is_same<_b, list<>>, meta::npos, lazy::minus<lazy::size<_a>, lazy::size<_b>>>>;
  141. static_assert(find_index_<int, list<short, int, float>>{} == 1, "");
  142. static_assert(find_index_<double, list<short, int, float>>{} == meta::npos{}, "");
  143. // Test that the unselected branch does not get evaluated:
  144. template<typename T>
  145. using test_lazy_if_ = let<lazy::if_<std::is_void<T>, T, defer<std::pair, T>>>;
  146. static_assert(std::is_same<test_lazy_if_<void>, void>::value, "");
  147. // Test that and_ gets short-circuited:
  148. template<typename T>
  149. using test_lazy_and_ = let<lazy::and_<std::is_void<T>, defer<std::is_convertible, T>>>;
  150. static_assert(std::is_same<test_lazy_and_<int>, std::false_type>::value, "");
  151. // Test that and_ gets short-circuited:
  152. template<typename T>
  153. using test_lazy_or_ = let<lazy::or_<std::is_void<T>, defer<std::is_convertible, T>>>;
  154. static_assert(std::is_same<test_lazy_or_<void>, std::true_type>::value, "");
  155. template<typename A, int B = 0>
  156. struct lambda_test
  157. {
  158. };
  159. template<typename N>
  160. struct fact
  161. : let<lazy::if_c<(N::value > 0), lazy::multiplies<N, defer<fact, dec<N>>>, meta::size_t<1>>>
  162. {
  163. };
  164. static_assert(fact<meta::size_t<0>>::value == 1, "");
  165. static_assert(fact<meta::size_t<1>>::value == 1, "");
  166. static_assert(fact<meta::size_t<2>>::value == 2, "");
  167. static_assert(fact<meta::size_t<3>>::value == 6, "");
  168. static_assert(fact<meta::size_t<4>>::value == 24, "");
  169. template<std::size_t N>
  170. struct fact2
  171. : let<lazy::if_c<(N > 0), lazy::multiplies<meta::size_t<N>, defer_i<std::size_t, fact2, N - 1>>,
  172. meta::size_t<1>>>
  173. {
  174. };
  175. static_assert(fact2<0>::value == 1, "");
  176. static_assert(fact2<1>::value == 1, "");
  177. static_assert(fact2<2>::value == 2, "");
  178. static_assert(fact2<3>::value == 6, "");
  179. static_assert(fact2<4>::value == 24, "");
  180. template<typename N>
  181. struct factorial
  182. : let<if_c<N::value == 0, meta::size_t<1>, lazy::multiplies<N, factorial<lazy::dec<N>>>>>
  183. {
  184. };
  185. static_assert(factorial<meta::size_t<0>>::value == 1, "");
  186. static_assert(factorial<meta::size_t<1>>::value == 1, "");
  187. static_assert(factorial<meta::size_t<2>>::value == 2, "");
  188. static_assert(factorial<meta::size_t<3>>::value == 6, "");
  189. static_assert(factorial<meta::size_t<4>>::value == 24, "");
  190. int main()
  191. {
  192. // meta::sizeof_
  193. static_assert(meta::sizeof_<int>{} == sizeof(int), "");
  194. // meta::min
  195. static_assert(meta::min<meta::size_t<0>, meta::size_t<1>>{} == 0, "");
  196. static_assert(meta::min<meta::size_t<0>, meta::size_t<0>>{} == 0, "");
  197. static_assert(meta::min<meta::size_t<1>, meta::size_t<0>>{} == 0, "");
  198. // meta::max
  199. static_assert(meta::max<meta::size_t<0>, meta::size_t<1>>{} == 1, "");
  200. static_assert(meta::max<meta::size_t<1>, meta::size_t<0>>{} == 1, "");
  201. static_assert(meta::max<meta::size_t<1>, meta::size_t<1>>{} == 1, "");
  202. // meta::filter
  203. {
  204. using l = meta::list<int, double, short, float, long, char>;
  205. using il = meta::list<int, short, long, char>;
  206. using fl = meta::list<double, float>;
  207. static_assert(std::is_same<il, meta::filter<l, meta::quote<std::is_integral>>>{}, "");
  208. static_assert(std::is_same<fl, meta::filter<l, meta::quote<std::is_floating_point>>>{}, "");
  209. }
  210. // meta::for_each
  211. {
  212. using l = meta::list<int, long, short>;
  213. constexpr auto r = meta::for_each(l{}, check_integral());
  214. static_assert(std::is_same<meta::_t<std::remove_cv<decltype(r)>>, check_integral>::value,
  215. "");
  216. }
  217. // meta::find_index
  218. {
  219. using l = meta::list<int, long, short, int>;
  220. static_assert(meta::find_index<l, int>{} == 0, "");
  221. static_assert(meta::find_index<l, long>{} == 1, "");
  222. static_assert(meta::find_index<l, short>{} == 2, "");
  223. static_assert(meta::find_index<l, double>{} == meta::npos{}, "");
  224. static_assert(meta::find_index<l, float>{} == meta::npos{}, "");
  225. using l2 = meta::list<>;
  226. static_assert(meta::find_index<l2, double>{} == meta::npos{}, "");
  227. using namespace meta::placeholders;
  228. using lambda = meta::lambda<_a, _b, meta::lazy::find_index<_b, _a>>;
  229. using result = meta::invoke<lambda, long, l>;
  230. static_assert(result{} == 1, "");
  231. }
  232. // meta::reverse_find_index
  233. {
  234. using l = meta::list<int, long, short, int>;
  235. static_assert(meta::reverse_find_index<l, int>{} == 3, "");
  236. static_assert(meta::reverse_find_index<l, long>{} == 1, "");
  237. static_assert(meta::reverse_find_index<l, short>{} == 2, "");
  238. static_assert(meta::reverse_find_index<l, double>{} == meta::npos{}, "");
  239. static_assert(meta::reverse_find_index<l, float>{} == meta::npos{}, "");
  240. using l2 = meta::list<>;
  241. static_assert(meta::reverse_find_index<l2, double>{} == meta::npos{}, "");
  242. using lambda = meta::lambda<_a, _b, meta::lazy::reverse_find_index<_b, _a>>;
  243. using result = meta::invoke<lambda, long, l>;
  244. static_assert(result{} == 1, "");
  245. }
  246. // meta::count
  247. {
  248. using l = meta::list<int, long, short, int>;
  249. static_assert(meta::count<l, int>{} == 2, "");
  250. static_assert(meta::count<l, short>{} == 1, "");
  251. static_assert(meta::count<l, double>{} == 0, "");
  252. }
  253. // meta::count_if
  254. {
  255. using l = meta::list<int, long, short, int>;
  256. static_assert(meta::count_if<l, lambda<_a, std::is_same<_a, int>>>{} == 2, "");
  257. static_assert(meta::count_if<l, lambda<_b, std::is_same<_b, short>>>{} == 1, "");
  258. static_assert(meta::count_if<l, lambda<_c, std::is_same<_c, double>>>{} == 0, "");
  259. }
  260. // pathological lambda test
  261. {
  262. using X = invoke<lambda<_a, lambda_test<_a>>, int>;
  263. static_assert(std::is_same<X, lambda_test<_a>>::value, "");
  264. }
  265. // meta::unique
  266. {
  267. using l = meta::list<int, short, int, double, short, double, double>;
  268. static_assert(std::is_same<meta::unique<l>, list<int, short, double>>::value, "");
  269. }
  270. // meta::in
  271. {
  272. static_assert(in<list<int, int, short, float>, int>::value, "");
  273. static_assert(in<list<int, int, short, float>, short>::value, "");
  274. static_assert(in<list<int, int, short, float>, float>::value, "");
  275. static_assert(!in<list<int, int, short, float>, double>::value, "");
  276. }
  277. // lambda with variadic placeholders
  278. {
  279. using X = invoke<lambda<_args, list<_args>>, int, short, double>;
  280. static_assert(std::is_same<X, list<int, short, double>>::value, "");
  281. using X2 = invoke<lambda<_a, lambda_test<_a>>, int>;
  282. static_assert(std::is_same<X2, lambda_test<_a>>::value, "");
  283. using Y = invoke<lambda<_args, defer<std::pair, _args>>, int, short>;
  284. static_assert(std::is_same<Y, std::pair<int, short>>::value, "");
  285. using Y2 = invoke<lambda<_args, list<_args, list<_args>>>, int, short>;
  286. static_assert(std::is_same<Y2, list<int, short, list<int, short>>>::value, "");
  287. using Z = invoke<lambda<_a, _args, list<int, _args, double, _a>>, short *, short, float>;
  288. static_assert(std::is_same<Z, list<int, short, float, double, short *>>::value, "");
  289. // Nesting variadic lambdas in non-variadic lambdas:
  290. using A = invoke<lambda<_a, lazy::invoke<lambda<_b, _args, list<_args, _b>>, _a,
  291. lazy::_t<std::add_pointer<_a>>,
  292. lazy::_t<std::add_lvalue_reference<_a>>>>,
  293. int>;
  294. static_assert(std::is_same<A, list<int *, int &, int>>::value, "");
  295. // Nesting non-variadic lambdas in variadic lambdas:
  296. using B = invoke<lambda<_a, _args, lazy::invoke<lambda<_b, list<_b, _args, _a>>, _a>>, int,
  297. short, double>;
  298. static_assert(std::is_same<B, list<int, short, double, int>>::value, "");
  299. // Nesting variadic lambdas in variadic lambdas:
  300. using ZZ = invoke<
  301. lambda<_a, _args_a,
  302. lazy::invoke<lambda<_b, _args_b, list<_b, _a, list<_args_b>, list<_args_a>>>,
  303. _args_a>>,
  304. int, short, float, double>;
  305. static_assert(
  306. std::is_same<ZZ,
  307. list<short, int, list<float, double>, list<short, float, double>>>::value,
  308. "");
  309. // I'm guessing this failure is due to GCC #64970
  310. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64970
  311. #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5
  312. static_assert(!can_invoke<lambda<_args, defer<std::pair, _args>>, int>::value, "");
  313. static_assert(!can_invoke<lambda<_args, defer<std::pair, _args>>, int, short, double>::value,
  314. "");
  315. static_assert(!can_invoke<lambda<_a, defer<std::pair, _a, _a>>, int, short>::value, "");
  316. static_assert(!can_invoke<lambda<_a, _b, _c, _args, defer<std::pair, _a, _a>>>::value, "");
  317. #endif
  318. }
  319. // Test for meta::sort
  320. {
  321. using L0 = list<char[5], char[3], char[2], char[6], char[1], char[5], char[10]>;
  322. using L2 = meta::sort<L0, lambda<_a, _b, lazy::less<lazy::sizeof_<_a>, lazy::sizeof_<_b>>>>;
  323. static_assert(
  324. std::is_same<
  325. L2, list<char[1], char[2], char[3], char[5], char[5], char[6], char[10]>>::value,
  326. "");
  327. }
  328. // Check the _z user-defined literal:
  329. static_assert(42_z == 42, "");
  330. // Check integer_range
  331. {
  332. constexpr std::size_t a = meta::fold<meta::as_list<meta::integer_range<std::size_t, 0, 5>>,
  333. meta::size_t<0>, meta::quote<meta::plus>>{};
  334. static_assert(a == 10, "");
  335. constexpr std::size_t b = meta::fold<meta::as_list<meta::integer_range<std::size_t, 5, 10>>,
  336. meta::size_t<0>, meta::quote<meta::plus>>{};
  337. static_assert(b == 35, "");
  338. constexpr std::size_t c = meta::fold<meta::as_list<meta::integer_range<std::size_t, 0, 20>>,
  339. meta::size_t<0>, meta::quote<meta::plus>>{};
  340. static_assert(c == 190, "");
  341. using d = meta::integer_range<std::size_t, 5, 10>;
  342. static_assert(std::is_same<d, meta::integer_sequence<std::size_t, 5, 6, 7, 8, 9>>{}, "");
  343. }
  344. // Check reverse_fold
  345. {
  346. constexpr std::size_t a = meta::reverse_fold<meta::as_list<meta::integer_range<std::size_t, 0, 5>>,
  347. meta::size_t<0>, meta::quote<meta::plus>>{};
  348. static_assert(a == 10, "");
  349. constexpr std::size_t b = meta::reverse_fold<meta::as_list<meta::integer_range<std::size_t, 5, 10>>,
  350. meta::size_t<0>, meta::quote<meta::plus>>{};
  351. static_assert(b == 35, "");
  352. constexpr std::size_t c = meta::reverse_fold<meta::as_list<meta::integer_range<std::size_t, 0, 20>>,
  353. meta::size_t<0>, meta::quote<meta::plus>>{};
  354. static_assert(c == 190, "");
  355. }
  356. test_tuple_cat();
  357. return ::test_result();
  358. }