apply.pass.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. // UNSUPPORTED: c++98, c++03, c++11, c++14
  9. // <tuple>
  10. // template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
  11. // Test with different ref/ptr/cv qualified argument types.
  12. #include <tuple>
  13. #include <array>
  14. #include <utility>
  15. #include <cassert>
  16. #include "test_macros.h"
  17. #include "type_id.h"
  18. // std::array is explicitly allowed to be initialized with A a = { init-list };.
  19. // Disable the missing braces warning for this reason.
  20. #include "disable_missing_braces_warning.h"
  21. constexpr int constexpr_sum_fn() { return 0; }
  22. template <class ...Ints>
  23. constexpr int constexpr_sum_fn(int x1, Ints... rest) { return x1 + constexpr_sum_fn(rest...); }
  24. struct ConstexprSumT {
  25. constexpr ConstexprSumT() = default;
  26. template <class ...Ints>
  27. constexpr int operator()(Ints... values) const {
  28. return constexpr_sum_fn(values...);
  29. }
  30. };
  31. void test_constexpr_evaluation()
  32. {
  33. constexpr ConstexprSumT sum_obj{};
  34. {
  35. using Tup = std::tuple<>;
  36. using Fn = int(&)();
  37. constexpr Tup t;
  38. static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 0, "");
  39. static_assert(std::apply(sum_obj, t) == 0, "");
  40. }
  41. {
  42. using Tup = std::tuple<int>;
  43. using Fn = int(&)(int);
  44. constexpr Tup t(42);
  45. static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 42, "");
  46. static_assert(std::apply(sum_obj, t) == 42, "");
  47. }
  48. {
  49. using Tup = std::tuple<int, long>;
  50. using Fn = int(&)(int, int);
  51. constexpr Tup t(42, 101);
  52. static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, "");
  53. static_assert(std::apply(sum_obj, t) == 143, "");
  54. }
  55. {
  56. using Tup = std::pair<int, long>;
  57. using Fn = int(&)(int, int);
  58. constexpr Tup t(42, 101);
  59. static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, "");
  60. static_assert(std::apply(sum_obj, t) == 143, "");
  61. }
  62. {
  63. using Tup = std::tuple<int, long, int>;
  64. using Fn = int(&)(int, int, int);
  65. constexpr Tup t(42, 101, -1);
  66. static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, "");
  67. static_assert(std::apply(sum_obj, t) == 142, "");
  68. }
  69. {
  70. using Tup = std::array<int, 3>;
  71. using Fn = int(&)(int, int, int);
  72. constexpr Tup t = {42, 101, -1};
  73. static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, "");
  74. static_assert(std::apply(sum_obj, t) == 142, "");
  75. }
  76. }
  77. enum CallQuals {
  78. CQ_None,
  79. CQ_LValue,
  80. CQ_ConstLValue,
  81. CQ_RValue,
  82. CQ_ConstRValue
  83. };
  84. template <class Tuple>
  85. struct CallInfo {
  86. CallQuals quals;
  87. TypeID const* arg_types;
  88. Tuple args;
  89. template <class ...Args>
  90. CallInfo(CallQuals q, Args&&... xargs)
  91. : quals(q), arg_types(&makeArgumentID<Args&&...>()), args(std::forward<Args>(xargs)...)
  92. {}
  93. };
  94. template <class ...Args>
  95. inline CallInfo<decltype(std::forward_as_tuple(std::declval<Args>()...))>
  96. makeCallInfo(CallQuals quals, Args&&... args) {
  97. return {quals, std::forward<Args>(args)...};
  98. }
  99. struct TrackedCallable {
  100. TrackedCallable() = default;
  101. template <class ...Args> auto operator()(Args&&... xargs) &
  102. { return makeCallInfo(CQ_LValue, std::forward<Args>(xargs)...); }
  103. template <class ...Args> auto operator()(Args&&... xargs) const&
  104. { return makeCallInfo(CQ_ConstLValue, std::forward<Args>(xargs)...); }
  105. template <class ...Args> auto operator()(Args&&... xargs) &&
  106. { return makeCallInfo(CQ_RValue, std::forward<Args>(xargs)...); }
  107. template <class ...Args> auto operator()(Args&&... xargs) const&&
  108. { return makeCallInfo(CQ_ConstRValue, std::forward<Args>(xargs)...); }
  109. };
  110. template <class ...ExpectArgs, class Tuple>
  111. void check_apply_quals_and_types(Tuple&& t) {
  112. TypeID const* const expect_args = &makeArgumentID<ExpectArgs...>();
  113. TrackedCallable obj;
  114. TrackedCallable const& cobj = obj;
  115. {
  116. auto ret = std::apply(obj, std::forward<Tuple>(t));
  117. assert(ret.quals == CQ_LValue);
  118. assert(ret.arg_types == expect_args);
  119. assert(ret.args == t);
  120. }
  121. {
  122. auto ret = std::apply(cobj, std::forward<Tuple>(t));
  123. assert(ret.quals == CQ_ConstLValue);
  124. assert(ret.arg_types == expect_args);
  125. assert(ret.args == t);
  126. }
  127. {
  128. auto ret = std::apply(std::move(obj), std::forward<Tuple>(t));
  129. assert(ret.quals == CQ_RValue);
  130. assert(ret.arg_types == expect_args);
  131. assert(ret.args == t);
  132. }
  133. {
  134. auto ret = std::apply(std::move(cobj), std::forward<Tuple>(t));
  135. assert(ret.quals == CQ_ConstRValue);
  136. assert(ret.arg_types == expect_args);
  137. assert(ret.args == t);
  138. }
  139. }
  140. void test_call_quals_and_arg_types()
  141. {
  142. using Tup = std::tuple<int, int const&, unsigned&&>;
  143. const int x = 42;
  144. unsigned y = 101;
  145. Tup t(-1, x, std::move(y));
  146. Tup const& ct = t;
  147. check_apply_quals_and_types<int&, int const&, unsigned&>(t);
  148. check_apply_quals_and_types<int const&, int const&, unsigned&>(ct);
  149. check_apply_quals_and_types<int&&, int const&, unsigned&&>(std::move(t));
  150. check_apply_quals_and_types<int const&&, int const&, unsigned&&>(std::move(ct));
  151. }
  152. struct NothrowMoveable {
  153. NothrowMoveable() noexcept = default;
  154. NothrowMoveable(NothrowMoveable const&) noexcept(false) {}
  155. NothrowMoveable(NothrowMoveable&&) noexcept {}
  156. };
  157. template <bool IsNoexcept>
  158. struct TestNoexceptCallable {
  159. template <class ...Args>
  160. NothrowMoveable operator()(Args...) const noexcept(IsNoexcept) { return {}; }
  161. };
  162. void test_noexcept()
  163. {
  164. TestNoexceptCallable<true> nec;
  165. TestNoexceptCallable<false> tc;
  166. {
  167. // test that the functions noexcept-ness is propagated
  168. using Tup = std::tuple<int, const char*, long>;
  169. Tup t;
  170. LIBCPP_ASSERT_NOEXCEPT(std::apply(nec, t));
  171. ASSERT_NOT_NOEXCEPT(std::apply(tc, t));
  172. }
  173. {
  174. // test that the noexcept-ness of the argument conversions is checked.
  175. using Tup = std::tuple<NothrowMoveable, int>;
  176. Tup t;
  177. ASSERT_NOT_NOEXCEPT(std::apply(nec, t));
  178. LIBCPP_ASSERT_NOEXCEPT(std::apply(nec, std::move(t)));
  179. }
  180. }
  181. namespace ReturnTypeTest {
  182. static int my_int = 42;
  183. template <int N> struct index {};
  184. void f(index<0>) {}
  185. int f(index<1>) { return 0; }
  186. int & f(index<2>) { return static_cast<int &>(my_int); }
  187. int const & f(index<3>) { return static_cast<int const &>(my_int); }
  188. int volatile & f(index<4>) { return static_cast<int volatile &>(my_int); }
  189. int const volatile & f(index<5>) { return static_cast<int const volatile &>(my_int); }
  190. int && f(index<6>) { return static_cast<int &&>(my_int); }
  191. int const && f(index<7>) { return static_cast<int const &&>(my_int); }
  192. int volatile && f(index<8>) { return static_cast<int volatile &&>(my_int); }
  193. int const volatile && f(index<9>) { return static_cast<int const volatile &&>(my_int); }
  194. int * f(index<10>) { return static_cast<int *>(&my_int); }
  195. int const * f(index<11>) { return static_cast<int const *>(&my_int); }
  196. int volatile * f(index<12>) { return static_cast<int volatile *>(&my_int); }
  197. int const volatile * f(index<13>) { return static_cast<int const volatile *>(&my_int); }
  198. template <int Func, class Expect>
  199. void test()
  200. {
  201. using RawInvokeResult = decltype(f(index<Func>{}));
  202. static_assert(std::is_same<RawInvokeResult, Expect>::value, "");
  203. using FnType = RawInvokeResult (*) (index<Func>);
  204. FnType fn = f;
  205. std::tuple<index<Func>> t; ((void)t);
  206. using InvokeResult = decltype(std::apply(fn, t));
  207. static_assert(std::is_same<InvokeResult, Expect>::value, "");
  208. }
  209. } // end namespace ReturnTypeTest
  210. void test_return_type()
  211. {
  212. using ReturnTypeTest::test;
  213. test<0, void>();
  214. test<1, int>();
  215. test<2, int &>();
  216. test<3, int const &>();
  217. test<4, int volatile &>();
  218. test<5, int const volatile &>();
  219. test<6, int &&>();
  220. test<7, int const &&>();
  221. test<8, int volatile &&>();
  222. test<9, int const volatile &&>();
  223. test<10, int *>();
  224. test<11, int const *>();
  225. test<12, int volatile *>();
  226. test<13, int const volatile *>();
  227. }
  228. int main(int, char**) {
  229. test_constexpr_evaluation();
  230. test_call_quals_and_arg_types();
  231. test_return_type();
  232. test_noexcept();
  233. return 0;
  234. }