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, c++23
10
11// <functional>
12
13// template<auto f> constexpr unspecified not_fn() noexcept;
14
15#include <functional>
16
17#include <bit>
18#include <cassert>
19#include <concepts>
20#include <type_traits>
21#include <utility>
22
23#include "test_macros.h"
24
25class BooleanTestable {
26 bool val_;
27
28public:
29 constexpr explicit BooleanTestable(bool val) : val_(val) {}
30 constexpr operator bool() const { return val_; }
31 constexpr BooleanTestable operator!() const { return BooleanTestable{!val_}; }
32};
33
34LIBCPP_STATIC_ASSERT(std::__boolean_testable<BooleanTestable>);
35
36class FakeBool {
37 int val_;
38
39public:
40 constexpr FakeBool(int val) : val_(val) {}
41 constexpr FakeBool operator!() const { return FakeBool{-val_}; }
42 constexpr bool operator==(int other) const { return val_ == other; }
43};
44
45template <bool IsNoexcept>
46struct MaybeNoexceptFn {
47 bool operator()() const noexcept(IsNoexcept); // not defined
48};
49
50template <bool IsNoexcept>
51struct MaybeNoexceptNegation {
52 bool operator!() noexcept(IsNoexcept); // not defined
53};
54
55template <bool IsNoexcept>
56MaybeNoexceptNegation<IsNoexcept> maybe_noexcept_negation() noexcept {
57 return {};
58}
59
60constexpr void basic_tests() {
61 { // Test constant functions
62 auto false_fn = std::not_fn<std::false_type{}>();
63 assert(false_fn());
64
65 auto true_fn = std::not_fn<std::true_type{}>();
66 assert(!true_fn());
67
68 static_assert(noexcept(std::not_fn<std::false_type{}>()));
69 static_assert(noexcept(std::not_fn<std::true_type{}>()));
70 }
71
72 { // Test function with one argument
73 auto is_odd = std::not_fn<[](auto x) { return x % 2 == 0; }>();
74 assert(is_odd(1));
75 assert(!is_odd(2));
76 assert(is_odd(3));
77 assert(!is_odd(4));
78 assert(is_odd(5));
79 }
80
81 { // Test function with multiple arguments
82 auto at_least_10 = [](auto... vals) { return (vals + ... + 0) >= 10; };
83 auto at_most_9 = std::not_fn<at_least_10>();
84 assert(at_most_9());
85 assert(at_most_9(1));
86 assert(at_most_9(1, 2, 3, 4, -1));
87 assert(at_most_9(3, 3, 2, 1, -2));
88 assert(!at_most_9(10, -1, 2));
89 assert(!at_most_9(5, 5));
90 static_assert(noexcept(std::not_fn<at_least_10>()));
91 }
92
93 { // Test function that returns boolean-testable type other than bool
94 auto is_product_even = [](auto... vals) { return BooleanTestable{(vals * ... * 1) % 2 == 0}; };
95 auto is_product_odd = std::not_fn<is_product_even>();
96 assert(is_product_odd());
97 assert(is_product_odd(1, 3, 5, 9));
98 assert(is_product_odd(3, 3, 3, 3));
99 assert(!is_product_odd(3, 5, 9, 11, 0));
100 assert(!is_product_odd(11, 7, 5, 3, 2));
101 static_assert(noexcept(std::not_fn<is_product_even>()));
102 }
103
104 { // Test function that returns non-boolean-testable type
105 auto sum = [](auto... vals) -> FakeBool { return (vals + ... + 0); };
106 auto negated_sum = std::not_fn<sum>();
107 assert(negated_sum() == 0);
108 assert(negated_sum(3) == -3);
109 assert(negated_sum(4, 5, 1, 3) == -13);
110 assert(negated_sum(4, 2, 5, 6, 1) == -18);
111 assert(negated_sum(-1, 3, 2, -8) == 4);
112 static_assert(noexcept(std::not_fn<sum>()));
113 }
114
115 { // Test member pointers
116 struct MemberPointerTester {
117 bool value = true;
118 constexpr bool not_value() const { return !value; }
119 constexpr bool value_and(bool other) noexcept { return value && other; }
120 };
121
122 MemberPointerTester tester;
123
124 auto not_mem_object = std::not_fn<&MemberPointerTester::value>();
125 assert(!not_mem_object(tester));
126 assert(!not_mem_object(std::as_const(tester)));
127 static_assert(noexcept(not_mem_object(tester)));
128 static_assert(noexcept(not_mem_object(std::as_const(t&: tester))));
129
130 auto not_nullary_mem_fn = std::not_fn<&MemberPointerTester::not_value>();
131 assert(not_nullary_mem_fn(tester));
132 static_assert(!noexcept(not_nullary_mem_fn(tester)));
133
134 auto not_unary_mem_fn = std::not_fn<&MemberPointerTester::value_and>();
135 assert(not_unary_mem_fn(tester, false));
136 static_assert(noexcept(not_unary_mem_fn(tester, false)));
137 static_assert(!std::is_invocable_v<decltype(not_unary_mem_fn), const MemberPointerTester&, bool>);
138 }
139}
140
141constexpr void test_perfect_forwarding_call_wrapper() {
142 { // Make sure we call the correctly cv-ref qualified operator()
143 // based on the value category of the not_fn<NTTP> unspecified-type.
144 struct X {
145 constexpr FakeBool operator()() & { return 1; }
146 constexpr FakeBool operator()() const& { return 2; }
147 constexpr FakeBool operator()() && { return 3; }
148 constexpr FakeBool operator()() const&& { return 4; }
149 };
150
151 auto f = std::not_fn<X{}>();
152 using F = decltype(f);
153 assert(static_cast<F&>(f)() == -2);
154 assert(static_cast<const F&>(f)() == -2);
155 assert(static_cast<F&&>(f)() == -2);
156 assert(static_cast<const F&&>(f)() == -2);
157 }
158
159 // Call to `not_fn<NTTP>` unspecified-type's operator() should always result in call to the const& overload of the underlying function object.
160 {
161 { // Make sure unspecified-type is still callable when we delete the & overload.
162 struct X {
163 FakeBool operator()() & = delete;
164 FakeBool operator()() const&;
165 FakeBool operator()() &&;
166 FakeBool operator()() const&&;
167 };
168
169 using F = decltype(std::not_fn<X{}>());
170 static_assert(std::invocable<F&>);
171 static_assert(std::invocable<const F&>);
172 static_assert(std::invocable<F>);
173 static_assert(std::invocable<const F>);
174 }
175
176 { // Make sure unspecified-type is not callable when we delete the const& overload.
177 struct X {
178 FakeBool operator()() &;
179 FakeBool operator()() const& = delete;
180 FakeBool operator()() &&;
181 FakeBool operator()() const&&;
182 };
183
184 using F = decltype(std::not_fn<X{}>());
185 static_assert(!std::invocable<F&>);
186 static_assert(!std::invocable<const F&>);
187 static_assert(!std::invocable<F>);
188 static_assert(!std::invocable<const F>);
189 }
190
191 { // Make sure unspecified-type is still callable when we delete the && overload.
192 struct X {
193 FakeBool operator()() &;
194 FakeBool operator()() const&;
195 FakeBool operator()() && = delete;
196 FakeBool operator()() const&&;
197 };
198
199 using F = decltype(std::not_fn<X{}>());
200 static_assert(std::invocable<F&>);
201 static_assert(std::invocable<const F&>);
202 static_assert(std::invocable<F>);
203 static_assert(std::invocable<const F>);
204 }
205
206 { // Make sure unspecified-type is still callable when we delete the const&& overload.
207 struct X {
208 FakeBool operator()() &;
209 FakeBool operator()() const&;
210 FakeBool operator()() &&;
211 FakeBool operator()() const&& = delete;
212 };
213
214 using F = decltype(std::not_fn<X{}>());
215 static_assert(std::invocable<F&>);
216 static_assert(std::invocable<const F&>);
217 static_assert(std::invocable<F>);
218 static_assert(std::invocable<const F>);
219 }
220 }
221
222 { // Test perfect forwarding
223 auto f = [](int& val) {
224 val = 5;
225 return false;
226 };
227
228 auto not_f = std::not_fn<f>();
229 int val = 0;
230 assert(not_f(val));
231 assert(val == 5);
232
233 using NotF = decltype(not_f);
234 static_assert(std::invocable<NotF, int&>);
235 static_assert(!std::invocable<NotF, int>);
236 }
237}
238
239constexpr void test_return_type() {
240 { // Test constructors and assignment operators
241 struct IsPowerOfTwo {
242 constexpr bool operator()(unsigned int x) const { return std::has_single_bit(x: x); }
243 };
244
245 auto is_not_power_of_2 = std::not_fn<IsPowerOfTwo{}>();
246 assert(is_not_power_of_2(5));
247 assert(!is_not_power_of_2(4));
248
249 auto moved = std::move(is_not_power_of_2);
250 assert(moved(5));
251 assert(!moved(4));
252
253 auto copied = is_not_power_of_2;
254 assert(copied(7));
255 assert(!copied(8));
256
257 moved = std::move(copied);
258 assert(copied(9));
259 assert(!copied(16));
260
261 copied = moved;
262 assert(copied(11));
263 assert(!copied(32));
264 }
265
266 { // Make sure `not_fn<NTTP>` unspecified-type's operator() is SFINAE-friendly.
267 using F = decltype(std::not_fn<[](int x) { return !x; }>());
268 static_assert(!std::is_invocable<F>::value);
269 static_assert(std::is_invocable<F, int>::value);
270 static_assert(!std::is_invocable<F, void*>::value);
271 static_assert(!std::is_invocable<F, int, int>::value);
272 }
273
274 { // Test noexceptness
275 auto always_noexcept = std::not_fn<MaybeNoexceptFn<true>{}>();
276 static_assert(noexcept(always_noexcept()));
277
278 auto never_noexcept = std::not_fn<MaybeNoexceptFn<false>{}>();
279 static_assert(!noexcept(never_noexcept()));
280
281 auto always_noexcept_negation = std::not_fn<maybe_noexcept_negation<true>>();
282 static_assert(noexcept(always_noexcept_negation()));
283
284 auto never_noexcept_negation = std::not_fn<maybe_noexcept_negation<false>>();
285 static_assert(!noexcept(never_noexcept_negation()));
286 }
287
288 { // Test calling volatile wrapper
289 using NotFn = decltype(std::not_fn<std::false_type{}>());
290 static_assert(!std::invocable<volatile NotFn&>);
291 static_assert(!std::invocable<const volatile NotFn&>);
292 static_assert(!std::invocable<volatile NotFn>);
293 static_assert(!std::invocable<const volatile NotFn>);
294 }
295}
296
297constexpr bool test() {
298 basic_tests();
299 test_perfect_forwarding_call_wrapper();
300 test_return_type();
301
302 return true;
303}
304
305int main(int, char**) {
306 test();
307 static_assert(test());
308
309 return 0;
310}
311

source code of libcxx/test/std/utilities/function.objects/func.not_fn/not_fn.nttp.pass.cpp