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
11
12// <experimental/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 <experimental/tuple>
19#include <array>
20#include <utility>
21#include <cassert>
22
23// std::array is explicitly allowed to be initialized with A a = { init-list };.
24// Disable the missing braces warning for this reason.
25#include "disable_missing_braces_warning.h"
26
27
28namespace ex = std::experimental;
29
30int call_with_value(int x, int y) { return (x + y); }
31int call_with_ref(int & x, int & y) { return (x + y); }
32int call_with_const_ref(int const & x, int const & y) { return (x + y); }
33int call_with_rvalue_ref(int && x, int && y) { return (x + y); }
34int call_with_pointer(int * x, int * y) { return (*x + *y); }
35int call_with_const_pointer(int const* x, int const * y) { return (*x + *y); }
36
37
38template <class Tuple>
39void test_values()
40{
41    {
42        Tuple t{1, 2};
43        assert(3 == ex::apply(call_with_value, t));
44    }
45    {
46        Tuple t{2, 2};
47        assert(4 == ex::apply(call_with_ref, t));
48    }
49    {
50        Tuple t{2, 3};
51        assert(5 == ex::apply(call_with_const_ref, t));
52    }
53    {
54        Tuple t{3, 3};
55        assert(6 == ex::apply(call_with_rvalue_ref, static_cast<Tuple &&>(t)));
56    }
57    {
58        Tuple const t{4, 4};
59        assert(8 == ex::apply(call_with_value, t));
60    }
61    {
62        Tuple const t{4, 5};
63        assert(9 == ex::apply(call_with_const_ref, t));
64    }
65}
66
67template <class Tuple>
68void test_refs()
69{
70    int x = 0;
71    int y = 0;
72    {
73        x = 1; y = 2;
74        Tuple t{x, y};
75        assert(3 == ex::apply(call_with_value, t));
76    }
77    {
78        x = 2; y = 2;
79        Tuple t{x, y};
80        assert(4 == ex::apply(call_with_ref, t));
81    }
82    {
83        x = 2; y = 3;
84        Tuple t{x, y};
85        assert(5 == ex::apply(call_with_const_ref, t));
86    }
87    {
88        x = 3; y = 3;
89        Tuple const t{x, y};
90        assert(6 == ex::apply(call_with_value, t));
91    }
92    {
93        x = 3; y = 4;
94        Tuple const t{x, y};
95        assert(7 == ex::apply(call_with_const_ref, t));
96    }
97}
98
99template <class Tuple>
100void test_const_refs()
101{
102    int x = 0;
103    int y = 0;
104    {
105        x = 1; y = 2;
106        Tuple t{x, y};
107        assert(3 == ex::apply(call_with_value, t));
108    }
109    {
110        x = 2; y = 3;
111        Tuple t{x, y};
112        assert(5 == ex::apply(call_with_const_ref, t));
113    }
114    {
115        x = 3; y = 3;
116        Tuple const t{x, y};
117        assert(6 == ex::apply(call_with_value, t));
118    }
119    {
120        x = 3; y = 4;
121        Tuple const t{x, y};
122        assert(7 == ex::apply(call_with_const_ref, t));
123    }
124}
125
126
127template <class Tuple>
128void test_pointer()
129{
130    int x = 0;
131    int y = 0;
132    {
133        x = 2; y = 2;
134        Tuple t{&x, &y};
135        assert(4 == ex::apply(call_with_pointer, t));
136    }
137    {
138        x = 2; y = 3;
139        Tuple t{&x, &y};
140        assert(5 == ex::apply(call_with_const_pointer, t));
141    }
142    {
143        x = 3; y = 4;
144        Tuple const t{&x, &y};
145        assert(7 == ex::apply(call_with_const_pointer, t));
146    }
147}
148
149
150template <class Tuple>
151void test_const_pointer()
152{
153    int x = 0;
154    int y = 0;
155    {
156        x = 2; y = 3;
157        Tuple t{&x, &y};
158        assert(5 == ex::apply(call_with_const_pointer, t));
159    }
160    {
161        x = 3; y = 4;
162        Tuple const t{&x, &y};
163        assert(7 == ex::apply(call_with_const_pointer, t));
164    }
165}
166
167
168int main()
169{
170    test_values<std::tuple<int, int>>();
171    test_values<std::pair<int, int>>();
172    test_values<std::array<int, 2>>();
173
174    test_refs<std::tuple<int &, int &>>();
175    test_refs<std::pair<int &, int &>>();
176
177    test_const_refs<std::tuple<int const &, int const &>>();
178    test_const_refs<std::pair<int const &, int const &>>();
179
180    test_pointer<std::tuple<int *, int *>>();
181    test_pointer<std::pair<int *, int *>>();
182    test_pointer<std::array<int *, 2>>();
183
184    test_const_pointer<std::tuple<int const *, int const *>>();
185    test_const_pointer<std::pair<int const *, int const *>>();
186    test_const_pointer<std::array<int const *, 2>>();
187}
188