[PATCH] Define std::__invoke_r for INVOKE<R>

Jonathan Wakely jwakely@redhat.com
Fri May 17 09:15:00 GMT 2019


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.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch.txt
Type: text/x-patch
Size: 986 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/libstdc++/attachments/20190517/ee6d6b19/attachment.bin>


More information about the Libstdc++ mailing list