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...>;

Reply via email to