This is an automated email from the ASF dual-hosted git repository.
pitrou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new 4c9c3735271 GH-50728: [C++] Remove `call_traits::argument_count` in
favor of `type_traits` (#50729)
4c9c3735271 is described below
commit 4c9c3735271ebde083a6de9b12cf34f1962deea1
Author: Alexander Taepper <[email protected]>
AuthorDate: Wed Aug 26 10:54:31 2026 +0200
GH-50728: [C++] Remove `call_traits::argument_count` in favor of
`type_traits` (#50729)
### Rationale for this change
As part of #50250 we slowly want to remove the custom metaprogramming
helpers
### What changes are included in this PR?
This removes `call_traits::argument_count` in favor of `type_traits`.
We could also remove `ContinueFuture::ForSignature` because
`std::invoke_result` already checks the signature.
### Are these changes tested?
Yes.
### Are there any user-facing changes?
No
* GitHub Issue: #50728
Authored-by: Alexander Taepper <[email protected]>
Signed-off-by: Antoine Pitrou <[email protected]>
---
cpp/src/arrow/util/async_generator.h | 5 +--
cpp/src/arrow/util/functional.h | 13 --------
cpp/src/arrow/util/future.h | 59 ++++++++++++++----------------------
cpp/src/arrow/util/thread_pool.h | 16 +++++-----
4 files changed, 34 insertions(+), 59 deletions(-)
diff --git a/cpp/src/arrow/util/async_generator.h
b/cpp/src/arrow/util/async_generator.h
index 056b842bb73..63cb01a9fe4 100644
--- a/cpp/src/arrow/util/async_generator.h
+++ b/cpp/src/arrow/util/async_generator.h
@@ -24,6 +24,7 @@
#include <limits>
#include <optional>
#include <queue>
+#include <type_traits>
#include "arrow/util/async_generator_fwd.h"
#include "arrow/util/async_util.h"
@@ -266,7 +267,7 @@ class MappingGenerator {
///
/// If the source generator is async-reentrant then this generator will be also
template <typename T, typename MapFn,
- typename Mapped = detail::result_of_t<MapFn(const T&)>,
+ typename Mapped = std::invoke_result_t<MapFn, const T&>,
typename V = typename EnsureFuture<Mapped>::type::ValueType>
AsyncGenerator<V> MakeMappedGenerator(AsyncGenerator<T> source_generator,
MapFn map) {
auto map_callback = [map = std::move(map)](const T& val) mutable ->
Future<V> {
@@ -286,7 +287,7 @@ AsyncGenerator<V> MakeMappedGenerator(AsyncGenerator<T>
source_generator, MapFn
///
/// If the source generator is async-reentrant then this generator will be also
template <typename T, typename MapFn,
- typename Mapped = detail::result_of_t<MapFn(const T&)>,
+ typename Mapped = std::invoke_result_t<MapFn, const T&>,
typename V = typename EnsureFuture<Mapped>::type::ValueType>
AsyncGenerator<T> MakeFlatMappedGenerator(AsyncGenerator<T> source_generator,
MapFn map) {
return MakeConcatenatedGenerator(
diff --git a/cpp/src/arrow/util/functional.h b/cpp/src/arrow/util/functional.h
index 14e09b6f8a6..4444b747c83 100644
--- a/cpp/src/arrow/util/functional.h
+++ b/cpp/src/arrow/util/functional.h
@@ -52,23 +52,10 @@ struct call_traits {
static typename std::tuple_element<I, std::tuple<A...>>::type
argument_type_impl(
R (F::*)(A...) &&);
- template <typename F, typename R, typename... A>
- static std::integral_constant<int, sizeof...(A)> argument_count_impl(R
(F::*)(A...));
-
- template <typename F, typename R, typename... A>
- static std::integral_constant<int, sizeof...(A)> argument_count_impl(R
(F::*)(A...)
-
const);
-
- template <typename F, typename R, typename... A>
- static std::integral_constant<int, sizeof...(A)> argument_count_impl(R
(F::*)(A...) &&);
-
/// If F is not overloaded, the argument types of its call operator can be
/// extracted via call_traits::argument_type<Index, F>
template <std::size_t I, typename F>
using argument_type =
decltype(argument_type_impl<I>(&std::decay<F>::type::operator()));
-
- template <typename F>
- using argument_count =
decltype(argument_count_impl(&std::decay<F>::type::operator()));
};
/// A type erased callable object which may only be invoked once.
diff --git a/cpp/src/arrow/util/future.h b/cpp/src/arrow/util/future.h
index 0aa28427037..fa45427a9d3 100644
--- a/cpp/src/arrow/util/future.h
+++ b/cpp/src/arrow/util/future.h
@@ -50,18 +50,6 @@ struct is_future : std::false_type {};
template <typename T>
struct is_future<Future<T>> : std::true_type {};
-template <typename Signature, typename Enable = void>
-struct result_of;
-
-template <typename Fn, typename... A>
-struct result_of<Fn(A...),
-
internal::void_t<decltype(std::declval<Fn>()(std::declval<A>()...))>> {
- using type = decltype(std::declval<Fn>()(std::declval<A>()...));
-};
-
-template <typename Signature>
-using result_of_t = typename result_of<Signature>::type;
-
// Helper to find the synchronous counterpart for a Future
template <typename T>
struct SyncType {
@@ -75,12 +63,15 @@ struct SyncType<internal::Empty> {
template <typename Fn>
using first_arg_is_status =
- std::is_same<typename std::decay<internal::call_traits::argument_type<0,
Fn>>::type,
- Status>;
+ std::is_same<std::decay_t<internal::call_traits::argument_type<0, Fn>>,
Status>;
-template <typename Fn, typename Then, typename Else,
- typename Count = internal::call_traits::argument_count<Fn>>
-using if_has_no_args = typename std::conditional<Count::value == 0, Then,
Else>::type;
+template <typename Fn, typename Then, typename Else>
+using if_has_no_args = std::conditional_t<std::is_invocable_v<Fn>, Then, Else>;
+
+template <typename OnSuccess, typename T>
+using continuation_result_t =
+ typename if_has_no_args<OnSuccess, std::invoke_result<OnSuccess>,
+ std::invoke_result<OnSuccess, const T&>>::type;
/// Creates a callback that can be added to a future to mark a `dest` future
finished
template <typename Source, typename Dest, bool SourceEmpty = Source::is_empty,
@@ -121,12 +112,9 @@ struct ContinueFuture {
template <typename Return>
using ForReturn = typename ForReturnImpl<Return>::type;
- template <typename Signature>
- using ForSignature = ForReturn<result_of_t<Signature>>;
-
// If the callback returns void then we return Future<> that always finishes
OK.
template <typename ContinueFunc, typename... Args,
- typename ContinueResult = result_of_t<ContinueFunc && (Args &&
...)>,
+ typename ContinueResult = std::invoke_result_t<ContinueFunc,
Args...>,
typename NextFuture = ForReturn<ContinueResult>>
typename std::enable_if<std::is_void<ContinueResult>::value>::type
operator()(
NextFuture next, ContinueFunc&& f, Args&&... a) const {
@@ -141,7 +129,7 @@ struct ContinueFuture {
/// If the callback returns Status and we return Future<> then also send the
callback
/// result as-is to the destination future.
template <typename ContinueFunc, typename... Args,
- typename ContinueResult = result_of_t<ContinueFunc && (Args &&
...)>,
+ typename ContinueResult = std::invoke_result_t<ContinueFunc,
Args...>,
typename NextFuture = ForReturn<ContinueResult>>
typename std::enable_if<
!std::is_void<ContinueResult>::value &&
!is_future<ContinueResult>::value &&
@@ -158,7 +146,7 @@ struct ContinueFuture {
/// OnSuccess callback is void/Status (e.g. you would get this calling the
one-arg
/// version of Then with an OnSuccess callback that returns void)
template <typename ContinueFunc, typename... Args,
- typename ContinueResult = result_of_t<ContinueFunc && (Args &&
...)>,
+ typename ContinueResult = std::invoke_result_t<ContinueFunc,
Args...>,
typename NextFuture = ForReturn<ContinueResult>>
typename std::enable_if<!std::is_void<ContinueResult>::value &&
!is_future<ContinueResult>::value &&
NextFuture::is_empty &&
@@ -171,7 +159,7 @@ struct ContinueFuture {
/// future and add a callback to the future given to us by the user that
forwards the
/// result to the future we just created
template <typename ContinueFunc, typename... Args,
- typename ContinueResult = result_of_t<ContinueFunc && (Args &&
...)>,
+ typename ContinueResult = std::invoke_result_t<ContinueFunc,
Args...>,
typename NextFuture = ForReturn<ContinueResult>>
typename std::enable_if<is_future<ContinueResult>::value>::type operator()(
NextFuture next, ContinueFunc&& f, Args&&... a) const {
@@ -507,7 +495,7 @@ class [[nodiscard]] Future {
/// Returns true if a callback was actually added and false if the callback
failed
/// to add because the future was marked complete.
template <typename CallbackFactory,
- typename OnComplete = detail::result_of_t<CallbackFactory()>,
+ typename OnComplete = std::invoke_result_t<CallbackFactory>,
typename Callback = WrapOnComplete<OnComplete>>
bool TryAddCallback(CallbackFactory callback_factory,
CallbackOptions opts = CallbackOptions::Defaults())
const {
@@ -516,16 +504,15 @@ class [[nodiscard]] Future {
template <typename OnSuccess, typename OnFailure>
struct ThenOnComplete {
- static constexpr bool has_no_args =
- internal::call_traits::argument_count<OnSuccess>::value == 0;
+ static constexpr bool has_no_args = std::is_invocable_v<OnSuccess>;
- using ContinuedFuture = detail::ContinueFuture::ForSignature<
- detail::if_has_no_args<OnSuccess, OnSuccess && (), OnSuccess && (const
T&)>>;
+ using ContinuedFuture =
+
detail::ContinueFuture::ForReturn<detail::continuation_result_t<OnSuccess, T>>;
- static_assert(
- std::is_same<detail::ContinueFuture::ForSignature<OnFailure && (const
Status&)>,
- ContinuedFuture>::value,
- "OnSuccess and OnFailure must continue with the same future type");
+ static_assert(std::is_same<detail::ContinueFuture::ForReturn<
+ std::invoke_result_t<OnFailure, const
Status&>>,
+ ContinuedFuture>::value,
+ "OnSuccess and OnFailure must continue with the same future
type");
struct DummyOnSuccess {
void operator()(const T&);
@@ -558,8 +545,8 @@ class [[nodiscard]] Future {
template <typename OnSuccess>
struct PassthruOnFailure {
- using ContinuedFuture = detail::ContinueFuture::ForSignature<
- detail::if_has_no_args<OnSuccess, OnSuccess && (), OnSuccess && (const
T&)>>;
+ using ContinuedFuture =
+
detail::ContinueFuture::ForReturn<detail::continuation_result_t<OnSuccess, T>>;
Result<typename ContinuedFuture::ValueType> operator()(const Status& s) {
return s; }
};
@@ -803,7 +790,7 @@ using ControlFlow = std::optional<T>;
/// \return A future which will complete when a Future returned by iterate
completes with
/// a Break
template <typename Iterate,
- typename Control = typename
detail::result_of_t<Iterate()>::ValueType,
+ typename Control = typename std::invoke_result_t<Iterate>::ValueType,
typename BreakValueType = typename Control::value_type>
Future<BreakValueType> Loop(Iterate iterate) {
struct Callback {
diff --git a/cpp/src/arrow/util/thread_pool.h b/cpp/src/arrow/util/thread_pool.h
index 201b8cef790..ce33c4c201b 100644
--- a/cpp/src/arrow/util/thread_pool.h
+++ b/cpp/src/arrow/util/thread_pool.h
@@ -139,8 +139,8 @@ class ARROW_EXPORT Executor {
// will return the callable's result value once.
// The callable's arguments are copied before execution.
template <typename Function, typename... Args,
- typename FutureType = typename
::arrow::detail::ContinueFuture::ForSignature<
- Function && (Args && ...)>>
+ typename FutureType = ::arrow::detail::ContinueFuture::ForReturn<
+ std::invoke_result_t<Function, Args...>>>
Result<FutureType> Submit(TaskHints hints, StopToken stop_token, Function&&
func,
Args&&... args) {
using ValueType = typename FutureType::ValueType;
@@ -165,24 +165,24 @@ class ARROW_EXPORT Executor {
}
template <typename Function, typename... Args,
- typename FutureType = typename
::arrow::detail::ContinueFuture::ForSignature<
- Function && (Args && ...)>>
+ typename FutureType = ::arrow::detail::ContinueFuture::ForReturn<
+ std::invoke_result_t<Function, Args...>>>
Result<FutureType> Submit(StopToken stop_token, Function&& func, Args&&...
args) {
return Submit(TaskHints{}, stop_token, std::forward<Function>(func),
std::forward<Args>(args)...);
}
template <typename Function, typename... Args,
- typename FutureType = typename
::arrow::detail::ContinueFuture::ForSignature<
- Function && (Args && ...)>>
+ typename FutureType = ::arrow::detail::ContinueFuture::ForReturn<
+ std::invoke_result_t<Function, Args...>>>
Result<FutureType> Submit(TaskHints hints, Function&& func, Args&&... args) {
return Submit(std::move(hints), StopToken::Unstoppable(),
std::forward<Function>(func), std::forward<Args>(args)...);
}
template <typename Function, typename... Args,
- typename FutureType = typename
::arrow::detail::ContinueFuture::ForSignature<
- Function && (Args && ...)>>
+ typename FutureType = ::arrow::detail::ContinueFuture::ForReturn<
+ std::invoke_result_t<Function, Args...>>>
Result<FutureType> Submit(Function&& func, Args&&... args) {
return Submit(TaskHints{}, StopToken::Unstoppable(),
std::forward<Function>(func),
std::forward<Args>(args)...);