On 17/05/19 10:49 +0200, Stephan Bergmann wrote:
On 14/05/2019 17:25, Jonathan Wakely wrote:
* include/bits/invoke.h (__invoke_r): Define new function implementing
the INVOKE<R> pseudo-function.
* testsuite/20_util/function_objects/invoke/1.cc: Add more tests.
* testsuite/20_util/function_objects/invoke/2.cc: New test.
Tested powerpc64le-linux, committed to trunk.
diff --git a/libstdc++-v3/include/bits/invoke.h
b/libstdc++-v3/include/bits/invoke.h
index a5278a59f0c..59e22da84d4 100644
--- a/libstdc++-v3/include/bits/invoke.h
+++ b/libstdc++-v3/include/bits/invoke.h
@@ -96,6 +96,65 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
std::forward<_Args>(__args)...);
}
+#if __cplusplus >= 201703L
+ // INVOKE<R>: Invoke a callable object and convert the result to R.
+ template<typename _Res, typename _Callable, typename... _Args>
+ constexpr enable_if_t<is_invocable_r_v<_Res, _Callable, _Args...>, _Res>
+ __invoke_r(_Callable&& __fn, _Args&&... __args)
+ noexcept(is_nothrow_invocable_r_v<_Res, _Callable, _Args...>)
+ {
+ using __result = __invoke_result<_Callable, _Args...>;
+ using __type = typename __result::type;
+ using __tag = typename __result::__invoke_type;
+ if constexpr (is_void_v<_Res>)
+ std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
+ std::forward<_Args>(__args)...);
+ else
+ return std::__invoke_impl<__type>(__tag{},
+ std::forward<_Callable>(__fn),
+ std::forward<_Args>(__args)...);
+ }
+#else // C++11
+ template<typename _Res, typename _Callable, typename... _Args>
+ using __can_invoke_as_void = __enable_if_t<
+ __and_<is_void<_Res>, __is_invocable<_Callable, _Args...>>::value,
+ _Res
+ >;
+
+ template<typename _Res, typename _Callable, typename... _Args>
+ using __can_invoke_as_nonvoid = __enable_if_t<
+ __and_<__not_<is_void<_Res>>,
+ is_convertible<typename __invoke_result<_Callable, _Args...>::type,
+ _Res>
+ >::value,
+ _Res
+ >;
+
+ // INVOKE<R>: Invoke a callable object and convert the result to R.
+ template<typename _Res, typename _Callable, typename... _Args>
+ constexpr __can_invoke_as_nonvoid<_Res, _Callable, _Args...>
+ __invoke_r(_Callable&& __fn, _Args&&... __args)
+ {
+ using __result = __invoke_result<_Callable, _Args...>;
+ using __type = typename __result::type;
+ using __tag = typename __result::__invoke_type;
+ return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
+ std::forward<_Args>(__args)...);
+ }
+
+ // INVOKE<R> when R is cv void
+ template<typename _Res, typename _Callable, typename... _Args>
+ constexpr __can_invoke_as_void<_Res, _Callable, _Args...>
+ __invoke_r(_Callable&& __fn, _Args&&... __args)
I think this is a problem with -std=c++11 (but not -std=c++14) where
void is not yet a literal type, so this function can't be constexpr?
Yes, Clang diagnoses this in C++11 mode but G++ accepts it (unless you
actually try to call g<T>() in a constant expression):
template<typename T> struct voidy { using type = void; };
template<typename T> constexpr typename voidy<T>::type g() {}
$ clang++ v.cc -std=c++11
v.cc:2:56: error: no return statement in constexpr function
template<typename T> constexpr typename voidy<T>::type g() {}
^
1 error generated.
I'm testing the attached fix. Thanks for the report.
commit 6ae6283255f58ad44a159970dce6f431cf46f293
Author: Jonathan Wakely <jwak...@redhat.com>
Date: Fri May 17 10:10:10 2019 +0100
Fix __invoke_r<void> to be valid in C++11
* include/bits/invoke.h [__cplusplus < 201703L] (__invoke_r<void>):
Use _GLIBCXX14_CONSTEXPR because void functions cannot be constexpr
in C++11.
diff --git a/libstdc++-v3/include/bits/invoke.h b/libstdc++-v3/include/bits/invoke.h
index 59e22da84d4..b2e9eee1a48 100644
--- a/libstdc++-v3/include/bits/invoke.h
+++ b/libstdc++-v3/include/bits/invoke.h
@@ -144,7 +144,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// INVOKE<R> when R is cv void
template<typename _Res, typename _Callable, typename... _Args>
- constexpr __can_invoke_as_void<_Res, _Callable, _Args...>
+ _GLIBCXX14_CONSTEXPR __can_invoke_as_void<_Res, _Callable, _Args...>
__invoke_r(_Callable&& __fn, _Args&&... __args)
{
using __result = __invoke_result<_Callable, _Args...>;