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

Stephan Bergmann sbergman@redhat.com
Fri May 17 08:49:00 GMT 2019


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?

(I came across this with Clang -std=c++11 upon #include <memory> 
producing an odd

> In file included from /home/sbergman/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/10.0.0/../../../../include/c++/10.0.0/memory:81:
> In file included from /home/sbergman/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/10.0.0/../../../../include/c++/10.0.0/bits/unique_ptr.h:37:
> In file included from /home/sbergman/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/10.0.0/../../../../include/c++/10.0.0/tuple:41:
> /home/sbergman/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/10.0.0/../../../../include/c++/10.0.0/bits/invoke.h:148:5: error: no return statement in constexpr function
>     __invoke_r(_Callable&& __fn, _Args&&... __args)
>     ^

I first reduced that to a broken reproducer and misclassified it as a 
Clang bug, <https://bugs.llvm.org/show_bug.cgi?id=41896> "Bogus 'error: 
no return statement in constexpr function' when void return type is 
'templated'".  But what apparently happens is that since Clang knows 
that the constexpr function must have a literal return type (which can't 
be void for -std=c++11), it just issues that error whenever it comes a 
constexpr function that lacks a return type.)

> +    {
> +      using __result = __invoke_result<_Callable, _Args...>;
> +      using __type = typename __result::type;
> +      using __tag = typename __result::__invoke_type;
> +      std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
> +				 std::forward<_Args>(__args)...);
> +    }
> +#endif // C++11
> +
>  _GLIBCXX_END_NAMESPACE_VERSION
>  } // namespace std
>  



More information about the Gcc-patches mailing list