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 |
10 | |
11 | // template<class F, class I> |
12 | // concept indirectly_regular_unary_invocable; |
13 | |
14 | #include <iterator> |
15 | #include <concepts> |
16 | |
17 | #include "indirectly_readable.h" |
18 | #include "test_macros.h" |
19 | |
20 | using It = IndirectlyReadable<struct Token>; |
21 | using R1 = T1<struct ReturnToken>; |
22 | using R2 = T2<struct ReturnToken>; |
23 | |
24 | template <class I> |
25 | struct GoodInvocable { |
26 | R1 operator()(std::iter_value_t<I>&) const; |
27 | R2 operator()(std::iter_reference_t<I>) const; |
28 | R2 operator()(std::iter_common_reference_t<I>) const; |
29 | }; |
30 | |
31 | // Should work when all constraints are satisfied |
32 | static_assert(std::indirectly_regular_unary_invocable<GoodInvocable<It>, It>); |
33 | |
34 | // Should fail when the iterator is not indirectly_readable |
35 | struct NotIndirectlyReadable { }; |
36 | static_assert(!std::indirectly_regular_unary_invocable<GoodInvocable<NotIndirectlyReadable>, NotIndirectlyReadable>); |
37 | |
38 | // Should fail when the invocable is not copy constructible |
39 | struct BadInvocable1 { |
40 | BadInvocable1(BadInvocable1 const&) = delete; |
41 | template <class T> R1 operator()(T const&) const; |
42 | }; |
43 | static_assert(!std::indirectly_regular_unary_invocable<BadInvocable1, It>); |
44 | |
45 | // Should fail when the invocable can't be called with (iter_value_t&) |
46 | struct BadInvocable2 { |
47 | template <class T> R1 operator()(T const&) const; |
48 | R1 operator()(std::iter_value_t<It>&) const = delete; |
49 | }; |
50 | static_assert(!std::indirectly_regular_unary_invocable<BadInvocable2, It>); |
51 | |
52 | // Should fail when the invocable can't be called with (iter_reference_t) |
53 | struct BadInvocable3 { |
54 | template <class T> R1 operator()(T const&) const; |
55 | R1 operator()(std::iter_reference_t<It>) const = delete; |
56 | }; |
57 | static_assert(!std::indirectly_regular_unary_invocable<BadInvocable3, It>); |
58 | |
59 | // Should fail when the invocable can't be called with (iter_common_reference_t) |
60 | struct BadInvocable4 { |
61 | template <class T> R1 operator()(T const&) const; |
62 | R1 operator()(std::iter_common_reference_t<It>) const = delete; |
63 | }; |
64 | static_assert(!std::indirectly_regular_unary_invocable<BadInvocable4, It>); |
65 | |
66 | // Should fail when the invocable doesn't have a common reference between its return types |
67 | struct BadInvocable5 { |
68 | R1 operator()(std::iter_value_t<It>&) const; |
69 | struct Unrelated { }; |
70 | Unrelated operator()(std::iter_reference_t<It>) const; |
71 | R1 operator()(std::iter_common_reference_t<It>) const; |
72 | }; |
73 | static_assert(!std::indirectly_regular_unary_invocable<BadInvocable5, It>); |
74 | |
75 | // Various tests with callables |
76 | struct S; |
77 | static_assert(std::indirectly_regular_unary_invocable<int (*)(int), int*>); |
78 | static_assert(std::indirectly_regular_unary_invocable<int (&)(int), int*>); |
79 | static_assert(std::indirectly_regular_unary_invocable<int S::*, S*>); |
80 | static_assert(std::indirectly_regular_unary_invocable<int (S::*)(), S*>); |
81 | static_assert(std::indirectly_regular_unary_invocable<int (S::*)() const, S*>); |
82 | static_assert(std::indirectly_regular_unary_invocable<void(*)(int), int*>); |
83 | |
84 | static_assert(!std::indirectly_regular_unary_invocable<int(int), int*>); // not move constructible |
85 | static_assert(!std::indirectly_regular_unary_invocable<int (*)(int*, int*), int*>); |
86 | static_assert(!std::indirectly_regular_unary_invocable<int (&)(int*, int*), int*>); |
87 | static_assert(!std::indirectly_regular_unary_invocable<int (S::*)(int*), S*>); |
88 | static_assert(!std::indirectly_regular_unary_invocable<int (S::*)(int*) const, S*>); |
89 | |
90 | // Test ADL-proofing (P2538R1) |
91 | #if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION) |
92 | struct Incomplete; |
93 | template<class T> struct Holder { T t; }; |
94 | struct HolderIncompletePred { bool operator()(Holder<Incomplete>*) const; }; |
95 | static_assert(std::indirectly_regular_unary_invocable<HolderIncompletePred, Holder<Incomplete>**>); |
96 | static_assert(!std::indirectly_regular_unary_invocable<Holder<Incomplete>*, Holder<Incomplete>**>); |
97 | #endif |
98 | |