1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
13 // template<class R, class F, class... Args>
14 // constexpr R invoke_r(F&& f, Args&&... args) // C++23
15 // noexcept(is_nothrow_invocable_r_v<R, F, Args...>);
20 #include <type_traits>
21 #include <utility> // declval
23 template <class R
, class F
, class ...Args
>
24 concept can_invoke_r
= requires
{
25 { std::invoke_r
<R
>(std::declval
<F
>(), std::declval
<Args
>()...) } -> std::same_as
<R
>;
28 constexpr bool test() {
29 // Make sure basic functionality works (i.e. we actually call the function and
30 // return the right result).
32 auto f
= [](int i
) { return i
+ 3; };
33 assert(std::invoke_r
<int>(f
, 4) == 7);
36 // Make sure invoke_r is SFINAE-friendly
38 auto f
= [](int) -> char* { return nullptr; };
39 static_assert( can_invoke_r
<char*, decltype(f
), int>);
40 static_assert( can_invoke_r
<void*, decltype(f
), int>);
41 static_assert( can_invoke_r
<void, decltype(f
), int>); // discard return type
42 static_assert(!can_invoke_r
<char*, decltype(f
), void*>); // wrong argument type
43 static_assert(!can_invoke_r
<char*, decltype(f
)>); // missing argument
44 static_assert(!can_invoke_r
<int*, decltype(f
), int>); // incompatible return type
45 static_assert(!can_invoke_r
<void, decltype(f
), void*>); // discard return type, invalid argument type
48 // Make sure invoke_r has the right noexcept specification
50 auto f
= [](int) noexcept(true) -> char* { return nullptr; };
51 auto g
= [](int) noexcept(false) -> char* { return nullptr; };
52 struct ConversionNotNoexcept
{
53 constexpr ConversionNotNoexcept(char*) noexcept(false) { }
55 static_assert( noexcept(std::invoke_r
<char*>(f
, 0)));
56 static_assert(!noexcept(std::invoke_r
<char*>(g
, 0))); // function call is not noexcept
57 static_assert(!noexcept(std::invoke_r
<ConversionNotNoexcept
>(f
, 0))); // function call is noexcept, conversion isn't
58 static_assert(!noexcept(std::invoke_r
<ConversionNotNoexcept
>(g
, 0))); // function call and conversion are both not noexcept
61 // Make sure invoke_r works with cv-qualified void return type
63 auto check
= []<class CV_Void
> {
64 bool was_called
= false;
65 auto f
= [&](int) -> char* { was_called
= true; return nullptr; };
66 std::invoke_r
<CV_Void
>(f
, 3);
68 static_assert(std::is_void_v
<decltype(std::invoke_r
<CV_Void
>(f
, 3))>);
70 check
.template operator()<void>();
71 check
.template operator()<void const>();
72 // volatile void is deprecated, so not testing it
73 // const volatile void is deprecated, so not testing it
76 // Make sure invoke_r forwards its arguments
79 NonCopyable() = default;
80 NonCopyable(NonCopyable
const&) = delete;
81 NonCopyable(NonCopyable
&&) = default;
83 // Forward argument, with void return
85 bool was_called
= false;
86 auto f
= [&](NonCopyable
) { was_called
= true; };
87 std::invoke_r
<void>(f
, NonCopyable());
90 // Forward argument, with non-void return
92 bool was_called
= false;
93 auto f
= [&](NonCopyable
) -> int { was_called
= true; return 0; };
94 (void)std::invoke_r
<int>(f
, NonCopyable());
97 // Forward function object, with void return
99 struct MoveOnlyVoidFunction
{
101 constexpr void operator()() && { was_called
= true; }
103 bool was_called
= false;
104 std::invoke_r
<void>(MoveOnlyVoidFunction
{was_called
});
107 // Forward function object, with non-void return
109 struct MoveOnlyIntFunction
{
111 constexpr int operator()() && { was_called
= true; return 0; }
113 bool was_called
= false;
114 (void)std::invoke_r
<int>(MoveOnlyIntFunction
{was_called
});
119 // Make sure invoke_r performs an implicit conversion of the result
122 constexpr operator int() const { return 42; }
124 auto f
= []() -> Convertible
{ return Convertible
{}; };
125 int result
= std::invoke_r
<int>(f
);
126 assert(result
== 42);
129 // Note: We don't test that `std::invoke_r` works with all kinds of callable types here,
130 // since that is extensively tested in the `std::invoke` tests.
135 int main(int, char**) {
137 static_assert(test());