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