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 |
10 | |
11 | // is_invocable_r |
12 | |
13 | #include <type_traits> |
14 | |
15 | // Non-invocable types |
16 | |
17 | static_assert(!std::is_invocable_r<void, void>::value); |
18 | static_assert(!std::is_invocable_r<void, int>::value); |
19 | static_assert(!std::is_invocable_r<void, int*>::value); |
20 | static_assert(!std::is_invocable_r<void, int&>::value); |
21 | static_assert(!std::is_invocable_r<void, int&&>::value); |
22 | |
23 | // Result type matches |
24 | |
25 | template <typename T> |
26 | T Return(); |
27 | |
28 | static_assert(std::is_invocable_r<int, decltype(Return<int>)>::value); |
29 | static_assert(std::is_invocable_r<char, decltype(Return<char>)>::value); |
30 | static_assert(std::is_invocable_r<int*, decltype(Return<int*>)>::value); |
31 | static_assert(std::is_invocable_r<int&, decltype(Return<int&>)>::value); |
32 | static_assert(std::is_invocable_r<int&&, decltype(Return<int&&>)>::value); |
33 | |
34 | // void result type |
35 | |
36 | // Any actual return type should be useable with a result type of void. |
37 | static_assert(std::is_invocable_r<void, decltype(Return<void>)>::value); |
38 | static_assert(std::is_invocable_r<void, decltype(Return<int>)>::value); |
39 | static_assert(std::is_invocable_r<void, decltype(Return<int*>)>::value); |
40 | static_assert(std::is_invocable_r<void, decltype(Return<int&>)>::value); |
41 | static_assert(std::is_invocable_r<void, decltype(Return<int&&>)>::value); |
42 | |
43 | // const- and volatile-qualified void should work too. |
44 | static_assert(std::is_invocable_r<const void, decltype(Return<void>)>::value); |
45 | static_assert(std::is_invocable_r<const void, decltype(Return<int>)>::value); |
46 | static_assert(std::is_invocable_r<volatile void, decltype(Return<void>)>::value); |
47 | static_assert(std::is_invocable_r<volatile void, decltype(Return<int>)>::value); |
48 | static_assert(std::is_invocable_r<const volatile void, decltype(Return<void>)>::value); |
49 | static_assert(std::is_invocable_r<const volatile void, decltype(Return<int>)>::value); |
50 | |
51 | // Conversion of result type |
52 | |
53 | // It should be possible to use a result type to which the actual return type |
54 | // can be converted. |
55 | static_assert(std::is_invocable_r<char, decltype(Return<int>)>::value); |
56 | static_assert(std::is_invocable_r<const int*, decltype(Return<int*>)>::value); |
57 | static_assert(std::is_invocable_r<void*, decltype(Return<int*>)>::value); |
58 | static_assert(std::is_invocable_r<const int&, decltype(Return<int>)>::value); |
59 | static_assert(std::is_invocable_r<const int&, decltype(Return<int&>)>::value); |
60 | static_assert(std::is_invocable_r<const int&, decltype(Return<int&&>)>::value); |
61 | static_assert(std::is_invocable_r<const char&, decltype(Return<int>)>::value); |
62 | |
63 | // But not a result type where the conversion doesn't work. |
64 | static_assert(!std::is_invocable_r<int, decltype(Return<void>)>::value); |
65 | static_assert(!std::is_invocable_r<int, decltype(Return<int*>)>::value); |
66 | |
67 | // Non-moveable result type |
68 | |
69 | // Define a type that can't be move-constructed. |
70 | struct CantMove { |
71 | CantMove() = default; |
72 | CantMove(CantMove&&) = delete; |
73 | }; |
74 | |
75 | static_assert(!std::is_move_constructible_v<CantMove>); |
76 | static_assert(!std::is_copy_constructible_v<CantMove>); |
77 | |
78 | // Define functions that return that type. |
79 | CantMove MakeCantMove() { return {}; } |
80 | CantMove MakeCantMoveWithArg(int) { return {}; } |
81 | |
82 | // Assumption check: it should be possible to call one of those functions and |
83 | // use it to initialize a CantMove object. |
84 | CantMove cant_move = MakeCantMove(); |
85 | |
86 | // Therefore std::is_invocable_r should agree that they can be invoked to yield |
87 | // a CantMove. |
88 | static_assert(std::is_invocable_r<CantMove, decltype(MakeCantMove)>::value); |
89 | static_assert(std::is_invocable_r<CantMove, decltype(MakeCantMoveWithArg), int>::value); |
90 | |
91 | // Of course it still shouldn't be possible to call one of the functions and get |
92 | // back some other type. |
93 | static_assert(!std::is_invocable_r<int, decltype(MakeCantMove)>::value); |
94 | |
95 | // And the argument types should still be important. |
96 | static_assert(!std::is_invocable_r<CantMove, decltype(MakeCantMove), int>::value); |
97 | static_assert(!std::is_invocable_r<CantMove, decltype(MakeCantMoveWithArg)>::value); |
98 | |
99 | // is_invocable_r |
100 | |
101 | // The struct form should be available too, not just the _v variant. |
102 | static_assert(std::is_invocable_r<int, decltype(Return<int>)>::value); |
103 | static_assert(!std::is_invocable_r<int*, decltype(Return<int>)>::value); |
104 | |