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