------------------------------------------------- -----------------
``__cpp_lib_forward_like`` ``202207L``
------------------------------------------------- -----------------
- ``__cpp_lib_invoke_r`` *unimplemented*
+ ``__cpp_lib_invoke_r`` ``202106L``
------------------------------------------------- -----------------
``__cpp_lib_is_scoped_enum`` ``202011L``
------------------------------------------------- -----------------
"`P1659R3 <https://wg21.link/P1659R3>`__","LWG","starts_with and ends_with","June 2021","","","|ranges|"
"`P1951R1 <https://wg21.link/P1951R1>`__","LWG","Default Arguments for pair Forwarding Constructor","June 2021","|Complete|","14.0"
"`P1989R2 <https://wg21.link/P1989R2>`__","LWG","Range constructor for std::string_view","June 2021","|Complete|","14.0","|ranges|"
-"`P2136R3 <https://wg21.link/P2136R3>`__","LWG","invoke_r","June 2021","",""
+"`P2136R3 <https://wg21.link/P2136R3>`__","LWG","invoke_r","June 2021","|Complete|","17.0"
"`P2166R1 <https://wg21.link/P2166R1>`__","LWG","A Proposal to Prohibit std::basic_string and std::basic_string_view construction from nullptr","June 2021","|Complete|","13.0"
"","","","","","",""
"`P0288R9 <https://wg21.link/P0288R9>`__","LWG","``any_invocable``","October 2021","",""
#endif // _LIBCPP_STD_VER > 14
+#if _LIBCPP_STD_VER >= 23
+template <class _Result, class _Fn, class... _Args>
+ requires is_invocable_r_v<_Result, _Fn, _Args...>
+_LIBCPP_HIDE_FROM_ABI constexpr _Result
+invoke_r(_Fn&& __f, _Args&&... __args) noexcept(is_nothrow_invocable_r_v<_Result, _Fn, _Args...>) {
+ if constexpr (is_void_v<_Result>) {
+ static_cast<void>(std::invoke(std::forward<_Fn>(__f), std::forward<_Args>(__args)...));
+ } else {
+ // TODO: Use reference_converts_from_temporary_v once implemented
+ // using _ImplicitInvokeResult = invoke_result_t<_Fn, _Args...>;
+ // static_assert(!reference_converts_from_temporary_v<_Result, _ImplicitInvokeResult>,
+ static_assert(true,
+ "Returning from invoke_r would bind a temporary object to the reference return type, "
+ "which would result in a dangling reference.");
+ return std::invoke(std::forward<_Fn>(__f), std::forward<_Args>(__args)...);
+ }
+}
+#endif
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___FUNCTIONAL_INVOKE_H
template<class R, class Fn, class... BoundArgs>
constexpr unspecified bind(Fn&&, BoundArgs&&...); // constexpr in C++20
+// [func.invoke]
template<class F, class... Args>
constexpr // constexpr in C++20
invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) // C++17
noexcept(is_nothrow_invocable_v<F, Args...>);
+template<class R, class F, class... Args>
+ constexpr R invoke_r(F&& f, Args&&... args) // C++23
+ noexcept(is_nothrow_invocable_r_v<R, F, Args...>);
+
namespace placeholders {
// M is the implementation-defined number of placeholders
extern unspecified _1;
# define __cpp_lib_constexpr_typeinfo 202106L
# define __cpp_lib_expected 202202L
# define __cpp_lib_forward_like 202207L
-// # define __cpp_lib_invoke_r 202106L
+# define __cpp_lib_invoke_r 202106L
# define __cpp_lib_is_scoped_enum 202011L
// # define __cpp_lib_move_only_function 202110L
# undef __cpp_lib_optional
# error "__cpp_lib_invoke should have the value 201411L in c++2b"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_invoke_r
-# error "__cpp_lib_invoke_r should be defined in c++2b"
-# endif
-# if __cpp_lib_invoke_r != 202106L
-# error "__cpp_lib_invoke_r should have the value 202106L in c++2b"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_invoke_r
-# error "__cpp_lib_invoke_r should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_invoke_r
+# error "__cpp_lib_invoke_r should be defined in c++2b"
+# endif
+# if __cpp_lib_invoke_r != 202106L
+# error "__cpp_lib_invoke_r should have the value 202106L in c++2b"
# endif
# if !defined(_LIBCPP_VERSION)
# error "__cpp_lib_invoke should have the value 201411L in c++2b"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_invoke_r
-# error "__cpp_lib_invoke_r should be defined in c++2b"
-# endif
-# if __cpp_lib_invoke_r != 202106L
-# error "__cpp_lib_invoke_r should have the value 202106L in c++2b"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_invoke_r
-# error "__cpp_lib_invoke_r should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_invoke_r
+# error "__cpp_lib_invoke_r should be defined in c++2b"
+# endif
+# if __cpp_lib_invoke_r != 202106L
+# error "__cpp_lib_invoke_r should have the value 202106L in c++2b"
# endif
# ifndef __cpp_lib_is_aggregate
+++ /dev/null
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <functional>
-
-// template <class F, class ...Args>
-// result_of_t<F&&(Args&&...)> invoke(F&&, Args&&...);
-
-#include <functional>
-#include <cassert>
-
-#include "test_macros.h"
-
-#if TEST_STD_VER <= 14
-# ifdef __cpp_lib_invoke
-# error Feature test macro should be defined
-# endif
-#else
-# ifndef __cpp_lib_invoke
-# error Feature test macro not defined
-# endif
-# if __cpp_lib_invoke != 201411
-# error __cpp_lib_invoke has the wrong value
-# endif
-#endif
-
-int foo(int) { return 42; }
-
-int main(int, char**) {
-#if defined(__cpp_lib_invoke)
- assert(std::invoke(foo, 101) == 42);
-#endif
-
- return 0;
-}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <functional>
+
+// template<class R, class F, class... Args>
+// constexpr R invoke_r(F&& f, Args&&... args) // C++23
+// noexcept(is_nothrow_invocable_r_v<R, F, Args...>);
+
+#include <cassert>
+#include <concepts>
+#include <functional>
+#include <type_traits>
+#include <utility> // declval
+
+template <class R, class F, class ...Args>
+concept can_invoke_r = requires {
+ { std::invoke_r<R>(std::declval<F>(), std::declval<Args>()...) } -> std::same_as<R>;
+};
+
+constexpr bool test() {
+ // Make sure basic functionality works (i.e. we actually call the function and
+ // return the right result).
+ {
+ auto f = [](int i) { return i + 3; };
+ assert(std::invoke_r<int>(f, 4) == 7);
+ }
+
+ // Make sure invoke_r is SFINAE-friendly
+ {
+ auto f = [](int) -> char* { return nullptr; };
+ static_assert( can_invoke_r<char*, decltype(f), int>);
+ static_assert( can_invoke_r<void*, decltype(f), int>);
+ static_assert( can_invoke_r<void, decltype(f), int>); // discard return type
+ static_assert(!can_invoke_r<char*, decltype(f), void*>); // wrong argument type
+ static_assert(!can_invoke_r<char*, decltype(f)>); // missing argument
+ static_assert(!can_invoke_r<int*, decltype(f), int>); // incompatible return type
+ static_assert(!can_invoke_r<void, decltype(f), void*>); // discard return type, invalid argument type
+ }
+
+ // Make sure invoke_r has the right noexcept specification
+ {
+ auto f = [](int) noexcept(true) -> char* { return nullptr; };
+ auto g = [](int) noexcept(false) -> char* { return nullptr; };
+ struct ConversionNotNoexcept {
+ constexpr ConversionNotNoexcept(char*) noexcept(false) { }
+ };
+ static_assert( noexcept(std::invoke_r<char*>(f, 0)));
+ static_assert(!noexcept(std::invoke_r<char*>(g, 0))); // function call is not noexcept
+ static_assert(!noexcept(std::invoke_r<ConversionNotNoexcept>(f, 0))); // function call is noexcept, conversion isn't
+ static_assert(!noexcept(std::invoke_r<ConversionNotNoexcept>(g, 0))); // function call and conversion are both not noexcept
+ }
+
+ // Make sure invoke_r works with cv-qualified void return type
+ {
+ auto check = []<class CV_Void> {
+ bool was_called = false;
+ auto f = [&](int) -> char* { was_called = true; return nullptr; };
+ std::invoke_r<CV_Void>(f, 3);
+ assert(was_called);
+ static_assert(std::is_void_v<decltype(std::invoke_r<CV_Void>(f, 3))>);
+ };
+ check.template operator()<void>();
+ check.template operator()<void const>();
+ // volatile void is deprecated, so not testing it
+ // const volatile void is deprecated, so not testing it
+ }
+
+ // Make sure invoke_r forwards its arguments
+ {
+ struct NonCopyable {
+ NonCopyable() = default;
+ NonCopyable(NonCopyable const&) = delete;
+ NonCopyable(NonCopyable&&) = default;
+ };
+ // Forward argument, with void return
+ {
+ bool was_called = false;
+ auto f = [&](NonCopyable) { was_called = true; };
+ std::invoke_r<void>(f, NonCopyable());
+ assert(was_called);
+ }
+ // Forward argument, with non-void return
+ {
+ bool was_called = false;
+ auto f = [&](NonCopyable) -> int { was_called = true; return 0; };
+ std::invoke_r<int>(f, NonCopyable());
+ assert(was_called);
+ }
+ // Forward function object, with void return
+ {
+ struct MoveOnlyVoidFunction {
+ bool& was_called;
+ constexpr void operator()() && { was_called = true; }
+ };
+ bool was_called = false;
+ std::invoke_r<void>(MoveOnlyVoidFunction{was_called});
+ assert(was_called);
+ }
+ // Forward function object, with non-void return
+ {
+ struct MoveOnlyIntFunction {
+ bool& was_called;
+ constexpr int operator()() && { was_called = true; return 0; }
+ };
+ bool was_called = false;
+ std::invoke_r<int>(MoveOnlyIntFunction{was_called});
+ assert(was_called);
+ }
+ }
+
+ // Make sure invoke_r performs an implicit conversion of the result
+ {
+ struct Convertible {
+ constexpr operator int() const { return 42; }
+ };
+ auto f = []() -> Convertible { return Convertible{}; };
+ int result = std::invoke_r<int>(f);
+ assert(result == 42);
+ }
+
+ // Note: We don't test that `std::invoke_r` works with all kinds of callable types here,
+ // since that is extensively tested in the `std::invoke` tests.
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <functional>
+
+// template<class R, class F, class... Args>
+// constexpr R invoke_r(F&& f, Args&&... args) // C++23
+// noexcept(is_nothrow_invocable_r_v<R, F, Args...>);
+//
+// Make sure that we diagnose when std::invoke_r is used with a return type that
+// would yield a dangling reference to a temporary.
+
+// TODO: We currently can't diagnose because we don't implement reference_converts_from_temporary.
+// XFAIL: *
+
+#include <functional>
+#include <cassert>
+
+#include "test_macros.h"
+
+void f() {
+ auto func = []() -> int { return 0; };
+ std::invoke_r<int&&>(func); // expected-error {{Returning from invoke_r would bind a temporary object}}
+}
"name": "__cpp_lib_invoke_r",
"values": { "c++2b": 202106 },
"headers": ["functional"],
- "unimplemented": True,
}, {
"name": "__cpp_lib_is_aggregate",
"values": { "c++17": 201703 },