xref: /llvm-project/libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp (revision ec350ad418a24f70c88758259c774a1e11c06d74)
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 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10 
11 // <optional>
12 
13 // template<class F> constexpr auto transform(F&&) &;
14 // template<class F> constexpr auto transform(F&&) &&;
15 // template<class F> constexpr auto transform(F&&) const&;
16 // template<class F> constexpr auto transform(F&&) const&&;
17 
18 #include "test_macros.h"
19 #include <cassert>
20 #include <optional>
21 #include <type_traits>
22 
23 struct LVal {
operator ()LVal24   constexpr int operator()(int&) { return 1; }
25   int operator()(const int&) = delete;
26   int operator()(int&&) = delete;
27   int operator()(const int&&) = delete;
28 };
29 
30 struct CLVal {
31   int operator()(int&) = delete;
operator ()CLVal32   constexpr int operator()(const int&) { return 1; }
33   int operator()(int&&) = delete;
34   int operator()(const int&&) = delete;
35 };
36 
37 struct RVal {
38   int operator()(int&) = delete;
39   int operator()(const int&) = delete;
operator ()RVal40   constexpr int operator()(int&&) { return 1; }
41   int operator()(const int&&) = delete;
42 };
43 
44 struct CRVal {
45   int operator()(int&) = delete;
46   int operator()(const int&) = delete;
47   int operator()(int&&) = delete;
operator ()CRVal48   constexpr int operator()(const int&&) { return 1; }
49 };
50 
51 struct RefQual {
operator ()RefQual52   constexpr int operator()(int) & { return 1; }
53   int operator()(int) const& = delete;
54   int operator()(int) && = delete;
55   int operator()(int) const&& = delete;
56 };
57 
58 struct CRefQual {
59   int operator()(int) & = delete;
operator ()CRefQual60   constexpr int operator()(int) const& { return 1; }
61   int operator()(int) && = delete;
62   int operator()(int) const&& = delete;
63 };
64 
65 struct RVRefQual {
66   int operator()(int) & = delete;
67   int operator()(int) const& = delete;
operator ()RVRefQual68   constexpr int operator()(int) && { return 1; }
69   int operator()(int) const&& = delete;
70 };
71 
72 struct RVCRefQual {
73   int operator()(int) & = delete;
74   int operator()(int) const& = delete;
75   int operator()(int) && = delete;
operator ()RVCRefQual76   constexpr int operator()(int) const&& { return 1; }
77 };
78 
79 struct NoCopy {
80   NoCopy() = default;
NoCopyNoCopy81   NoCopy(const NoCopy&) { assert(false); }
operator ()NoCopy82   int operator()(const NoCopy&&) { return 1; }
83 };
84 
85 struct NoMove {
86   NoMove() = default;
87   NoMove(NoMove&&) = delete;
operator ()NoMove88   NoMove operator()(const NoCopy&&) { return NoMove{}; }
89 };
90 
test_val_types()91 constexpr void test_val_types() {
92   // Test & overload
93   {
94     // Without & qualifier on F's operator()
95     {
96       std::optional<int> i{0};
97       assert(i.transform(LVal{}) == 1);
98       ASSERT_SAME_TYPE(decltype(i.transform(LVal{})), std::optional<int>);
99     }
100 
101     //With & qualifier on F's operator()
102     {
103       std::optional<int> i{0};
104       RefQual l{};
105       assert(i.transform(l) == 1);
106       ASSERT_SAME_TYPE(decltype(i.transform(l)), std::optional<int>);
107     }
108   }
109 
110   // Test const& overload
111   {
112     // Without & qualifier on F's operator()
113     {
114       const std::optional<int> i{0};
115       assert(i.transform(CLVal{}) == 1);
116       ASSERT_SAME_TYPE(decltype(i.transform(CLVal{})), std::optional<int>);
117     }
118 
119     //With & qualifier on F's operator()
120     {
121       const std::optional<int> i{0};
122       const CRefQual l{};
123       assert(i.transform(l) == 1);
124       ASSERT_SAME_TYPE(decltype(i.transform(l)), std::optional<int>);
125     }
126   }
127 
128   // Test && overload
129   {
130     // Without & qualifier on F's operator()
131     {
132       std::optional<int> i{0};
133       assert(std::move(i).transform(RVal{}) == 1);
134       ASSERT_SAME_TYPE(decltype(std::move(i).transform(RVal{})), std::optional<int>);
135     }
136 
137     //With & qualifier on F's operator()
138     {
139       std::optional<int> i{0};
140       assert(i.transform(RVRefQual{}) == 1);
141       ASSERT_SAME_TYPE(decltype(i.transform(RVRefQual{})), std::optional<int>);
142     }
143   }
144 
145   // Test const&& overload
146   {
147     // Without & qualifier on F's operator()
148     {
149       const std::optional<int> i{0};
150       assert(std::move(i).transform(CRVal{}) == 1);
151       ASSERT_SAME_TYPE(decltype(std::move(i).transform(CRVal{})), std::optional<int>);
152     }
153 
154     //With & qualifier on F's operator()
155     {
156       const std::optional<int> i{0};
157       const RVCRefQual l{};
158       assert(i.transform(std::move(l)) == 1);
159       ASSERT_SAME_TYPE(decltype(i.transform(std::move(l))), std::optional<int>);
160     }
161   }
162 }
163 
164 struct NonConst {
non_constNonConst165   int non_const() { return 1; }
166 };
167 
168 // check that the lambda body is not instantiated during overload resolution
test_sfinae()169 constexpr void test_sfinae() {
170   std::optional<NonConst> opt{};
171   auto l = [](auto&& x) { return x.non_const(); };
172   opt.transform(l);
173   std::move(opt).transform(l);
174 }
175 
test()176 constexpr bool test() {
177   test_sfinae();
178   test_val_types();
179   std::optional<int> opt;
180   const auto& copt = opt;
181 
182   const auto never_called = [](int) {
183     assert(false);
184     return 0;
185   };
186 
187   opt.transform(never_called);
188   std::move(opt).transform(never_called);
189   copt.transform(never_called);
190   std::move(copt).transform(never_called);
191 
192   std::optional<NoCopy> nc;
193   const auto& cnc = nc;
194   std::move(nc).transform(NoCopy{});
195   std::move(cnc).transform(NoCopy{});
196 
197   std::move(nc).transform(NoMove{});
198   std::move(cnc).transform(NoMove{});
199 
200   return true;
201 }
202 
main(int,char **)203 int main(int, char**) {
204   test();
205   static_assert(test());
206   return 0;
207 }
208