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 5d6cb93f3f GH-50713: [C++] Replace `return_type` and 
`enable_if_return` with <type_traits> helpers (#50714)
5d6cb93f3f is described below

commit 5d6cb93f3f47ebebcdbbf6fecdf48427415084de
Author: Alexander Taepper <[email protected]>
AuthorDate: Thu Jul 30 18:14:54 2026 +0200

    GH-50713: [C++] Replace `return_type` and `enable_if_return` with 
<type_traits> helpers (#50714)
    
    ### Rationale for this change
    
    This is the first part of simplifying functional helpers which are no 
longer required since the code-base supports more recent C++ versions. (See 
#50713 and #50250)
    
    ### What changes are included in this PR?
    
    This removes the `return_type` related helpers from `functional.h`. Also, 
the unused helpers `is_overloaded`, `enable_if_empty` and `enable_if_not_empty` 
are removed.
    
    ### Are these changes tested?
    
    Yes
    
    ### Are there any user-facing changes?
    
    No
    * GitHub Issue: #50713
    
    Authored-by: Alexander Taepper <[email protected]>
    Signed-off-by: Antoine Pitrou <[email protected]>
---
 cpp/src/arrow/compute/kernels/codegen_internal.h   | 14 ++++---
 .../compute/kernels/hash_aggregate_internal.h      | 15 +++++---
 cpp/src/arrow/util/cache_internal.h                |  5 +--
 cpp/src/arrow/util/functional.h                    | 43 ----------------------
 cpp/src/arrow/util/iterator.h                      | 21 ++++-------
 cpp/src/arrow/util/parallel.h                      |  6 +--
 cpp/src/arrow/util/vector.h                        | 10 ++---
 cpp/src/arrow/visit_data_inline.h                  | 32 +++++++++-------
 8 files changed, 54 insertions(+), 92 deletions(-)

diff --git a/cpp/src/arrow/compute/kernels/codegen_internal.h 
b/cpp/src/arrow/compute/kernels/codegen_internal.h
index fa89c86183..bfc529dc0a 100644
--- a/cpp/src/arrow/compute/kernels/codegen_internal.h
+++ b/cpp/src/arrow/compute/kernels/codegen_internal.h
@@ -23,6 +23,7 @@
 #include <optional>
 #include <string>
 #include <string_view>
+#include <type_traits>
 #include <utility>
 #include <vector>
 
@@ -479,9 +480,9 @@ struct UnboxScalar<Decimal256Type> {
 // values, such as Decimal128 rather than std::string_view.
 
 template <typename T, typename VisitFunc, typename NullFunc>
-static typename ::arrow::internal::call_traits::enable_if_return<VisitFunc, 
void>::type
-VisitArrayValuesInline(const ArraySpan& arr, VisitFunc&& valid_func,
-                       NullFunc&& null_func) {
+  requires std::is_void_v<std::invoke_result_t<VisitFunc, typename 
GetViewType<T>::T>>
+static void VisitArrayValuesInline(const ArraySpan& arr, VisitFunc&& 
valid_func,
+                                   NullFunc&& null_func) {
   VisitArraySpanInline<T>(
       arr,
       [&](typename GetViewType<T>::PhysicalType v) {
@@ -491,9 +492,10 @@ VisitArrayValuesInline(const ArraySpan& arr, VisitFunc&& 
valid_func,
 }
 
 template <typename T, typename VisitFunc, typename NullFunc>
-static typename ::arrow::internal::call_traits::enable_if_return<VisitFunc, 
Status>::type
-VisitArrayValuesInline(const ArraySpan& arr, VisitFunc&& valid_func,
-                       NullFunc&& null_func) {
+  requires std::is_same_v<std::invoke_result_t<VisitFunc, typename 
GetViewType<T>::T>,
+                          Status>
+static Status VisitArrayValuesInline(const ArraySpan& arr, VisitFunc&& 
valid_func,
+                                     NullFunc&& null_func) {
   return VisitArraySpanInline<T>(
       arr,
       [&](typename GetViewType<T>::PhysicalType v) {
diff --git a/cpp/src/arrow/compute/kernels/hash_aggregate_internal.h 
b/cpp/src/arrow/compute/kernels/hash_aggregate_internal.h
index f6462669ad..1ba21bd9b8 100644
--- a/cpp/src/arrow/compute/kernels/hash_aggregate_internal.h
+++ b/cpp/src/arrow/compute/kernels/hash_aggregate_internal.h
@@ -18,6 +18,7 @@
 #pragma once
 
 #include <memory>
+#include <type_traits>
 
 #include "arrow/array/data.h"
 #include "arrow/buffer_builder.h"
@@ -149,9 +150,10 @@ struct GroupedValueTraits<BooleanType> {
 };
 
 template <typename Type, typename ConsumeValue, typename ConsumeNull>
-typename arrow::internal::call_traits::enable_if_return<ConsumeValue, 
void>::type
-VisitGroupedValues(const ExecSpan& batch, ConsumeValue&& valid_func,
-                   ConsumeNull&& null_func) {
+  requires std::is_void_v<
+      std::invoke_result_t<ConsumeValue, uint32_t, typename 
GetViewType<Type>::T>>
+void VisitGroupedValues(const ExecSpan& batch, ConsumeValue&& valid_func,
+                        ConsumeNull&& null_func) {
   auto g = batch[1].array.GetValues<uint32_t>(1);
   if (batch[0].is_array()) {
     VisitArrayValuesInline<Type>(
@@ -174,9 +176,10 @@ VisitGroupedValues(const ExecSpan& batch, ConsumeValue&& 
valid_func,
 }
 
 template <typename Type, typename ConsumeValue, typename ConsumeNull>
-typename arrow::internal::call_traits::enable_if_return<ConsumeValue, 
Status>::type
-VisitGroupedValues(const ExecSpan& batch, ConsumeValue&& valid_func,
-                   ConsumeNull&& null_func) {
+  requires std::is_same_v<
+      std::invoke_result_t<ConsumeValue, uint32_t, typename 
GetViewType<Type>::T>, Status>
+Status VisitGroupedValues(const ExecSpan& batch, ConsumeValue&& valid_func,
+                          ConsumeNull&& null_func) {
   auto g = batch[1].array.GetValues<uint32_t>(1);
   if (batch[0].is_array()) {
     return VisitArrayValuesInline<Type>(
diff --git a/cpp/src/arrow/util/cache_internal.h 
b/cpp/src/arrow/util/cache_internal.h
index 05e4ef2a34..fe10af8bb2 100644
--- a/cpp/src/arrow/util/cache_internal.h
+++ b/cpp/src/arrow/util/cache_internal.h
@@ -167,9 +167,8 @@ struct ThreadUnsafeMemoizer {
 };
 
 template <template <typename...> class Cache, template <typename...> class 
MemoizerType,
-          typename Func,
-          typename Key = typename std::decay<call_traits::argument_type<0, 
Func>>::type,
-          typename Value = typename 
std::decay<call_traits::return_type<Func>>::type,
+          typename Func, typename Key = 
std::decay_t<call_traits::argument_type<0, Func>>,
+          typename Value = std::decay_t<std::invoke_result_t<Func, const 
Key&>>,
           typename Memoizer = MemoizerType<Key, Value, Cache<Key, Value>, 
Func>,
           typename RetType = typename Memoizer::RetType>
 static std::function<RetType(const Key&)> Memoize(Func&& func, int32_t 
cache_capacity) {
diff --git a/cpp/src/arrow/util/functional.h b/cpp/src/arrow/util/functional.h
index 41e268852f..14e09b6f8a 100644
--- a/cpp/src/arrow/util/functional.h
+++ b/cpp/src/arrow/util/functional.h
@@ -40,21 +40,6 @@ struct Empty {
 /// TODO(ARROW-12655) support function pointers
 struct call_traits {
  public:
-  template <typename R, typename... A>
-  static std::false_type is_overloaded_impl(R(A...));
-
-  template <typename F>
-  static std::false_type is_overloaded_impl(decltype(&F::operator())*);
-
-  template <typename F>
-  static std::true_type is_overloaded_impl(...);
-
-  template <typename F, typename R, typename... A>
-  static R return_type_impl(R (F::*)(A...));
-
-  template <typename F, typename R, typename... A>
-  static R return_type_impl(R (F::*)(A...) const);
-
   template <std::size_t I, typename F, typename R, typename... A>
   static typename std::tuple_element<I, std::tuple<A...>>::type 
argument_type_impl(
       R (F::*)(A...));
@@ -77,20 +62,6 @@ struct call_traits {
   template <typename F, typename R, typename... A>
   static std::integral_constant<int, sizeof...(A)> argument_count_impl(R 
(F::*)(A...) &&);
 
-  /// bool constant indicating whether F is a callable with more than one 
possible
-  /// signature. Will be true_type for objects which define multiple 
operator() or which
-  /// define a template operator()
-  template <typename F>
-  using is_overloaded =
-      decltype(is_overloaded_impl<typename std::decay<F>::type>(NULLPTR));
-
-  template <typename F, typename T = void>
-  using enable_if_overloaded = typename 
std::enable_if<is_overloaded<F>::value, T>::type;
-
-  template <typename F, typename T = void>
-  using disable_if_overloaded =
-      typename std::enable_if<!is_overloaded<F>::value, T>::type;
-
   /// 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>
@@ -98,20 +69,6 @@ struct call_traits {
 
   template <typename F>
   using argument_count = 
decltype(argument_count_impl(&std::decay<F>::type::operator()));
-
-  template <typename F>
-  using return_type = 
decltype(return_type_impl(&std::decay<F>::type::operator()));
-
-  template <typename F, typename T, typename RT = T>
-  using enable_if_return =
-      typename std::enable_if<std::is_same<return_type<F>, T>::value, RT>;
-
-  template <typename T, typename R = void>
-  using enable_if_empty = typename std::enable_if<std::is_same<T, 
Empty>::value, R>::type;
-
-  template <typename T, typename R = void>
-  using enable_if_not_empty =
-      typename std::enable_if<!std::is_same<T, Empty>::value, R>::type;
 };
 
 /// A type erased callable object which may only be invoked once.
diff --git a/cpp/src/arrow/util/iterator.h b/cpp/src/arrow/util/iterator.h
index dc7fd1d84c..aaf6531dfe 100644
--- a/cpp/src/arrow/util/iterator.h
+++ b/cpp/src/arrow/util/iterator.h
@@ -29,7 +29,6 @@
 #include "arrow/result.h"
 #include "arrow/status.h"
 #include "arrow/util/compare.h"
-#include "arrow/util/functional.h"
 #include "arrow/util/macros.h"
 #include "arrow/util/type_fwd.h"
 #include "arrow/util/visibility.h"
@@ -364,8 +363,7 @@ class FunctionIterator {
 };
 
 /// \brief Construct an Iterator which invokes a callable on Next()
-template <typename Fn,
-          typename Ret = typename 
internal::call_traits::return_type<Fn>::ValueType>
+template <typename Fn, typename Ret = typename 
std::invoke_result_t<Fn&>::ValueType>
 Iterator<Ret> MakeFunctionIterator(Fn fn) {
   return Iterator<Ret>(FunctionIterator<Fn, Ret>(std::move(fn)));
 }
@@ -455,15 +453,14 @@ class MapIterator {
 
 /// \brief MapIterator takes ownership of an iterator and a function to apply
 /// on every element. The mapped function is not allowed to fail.
-template <typename Fn, typename From = internal::call_traits::argument_type<0, 
Fn>,
-          typename To = internal::call_traits::return_type<Fn>>
+template <typename Fn, typename From, typename To = std::invoke_result_t<Fn&, 
From>>
 Iterator<To> MakeMapIterator(Fn map, Iterator<From> it) {
   return Iterator<To>(MapIterator<Fn, From, To>(std::move(map), 
std::move(it)));
 }
 
 /// \brief Like MapIterator, but where the function can fail.
-template <typename Fn, typename From = internal::call_traits::argument_type<0, 
Fn>,
-          typename To = typename 
internal::call_traits::return_type<Fn>::ValueType>
+template <typename Fn, typename From,
+          typename To = typename std::invoke_result_t<Fn&, From>::ValueType>
 Iterator<To> MakeMaybeMapIterator(Fn map, Iterator<From> it) {
   return Iterator<To>(MapIterator<Fn, From, To>(std::move(map), 
std::move(it)));
 }
@@ -520,12 +517,10 @@ struct FilterIterator {
 };
 
 /// \brief Like MapIterator, but where the function can fail or reject 
elements.
-template <
-    typename Fn, typename From = typename 
internal::call_traits::argument_type<0, Fn>,
-    typename Ret = typename internal::call_traits::return_type<Fn>::ValueType,
-    typename To = typename std::tuple_element<0, Ret>::type,
-    typename Enable = typename std::enable_if<std::is_same<
-        typename std::tuple_element<1, Ret>::type, 
FilterIterator::Action>::value>::type>
+template <typename Fn, typename From,
+          typename Ret = typename std::invoke_result_t<Fn&, From>::ValueType,
+          typename To = std::tuple_element_t<0, Ret>>
+  requires std::is_same_v<std::tuple_element_t<1, Ret>, FilterIterator::Action>
 Iterator<To> MakeFilterIterator(Fn filter, Iterator<From> it) {
   return Iterator<To>(
       FilterIterator::Impl<Fn, From, To>(std::move(filter), std::move(it)));
diff --git a/cpp/src/arrow/util/parallel.h b/cpp/src/arrow/util/parallel.h
index ae48a606e3..e9a530f0f9 100644
--- a/cpp/src/arrow/util/parallel.h
+++ b/cpp/src/arrow/util/parallel.h
@@ -17,11 +17,11 @@
 
 #pragma once
 
+#include <type_traits>
 #include <utility>
 #include <vector>
 
 #include "arrow/status.h"
-#include "arrow/util/functional.h"
 #include "arrow/util/thread_pool.h"
 #include "arrow/util/vector.h"
 
@@ -47,7 +47,7 @@ Status ParallelFor(int num_tasks, FUNCTION&& func,
 }
 
 template <class FUNCTION, typename T,
-          typename R = typename 
internal::call_traits::return_type<FUNCTION>::ValueType>
+          typename R = typename std::invoke_result_t<FUNCTION, int, 
T>::ValueType>
 Future<std::vector<R>> ParallelForAsync(std::vector<T> inputs, FUNCTION&& func,
                                         Executor* executor = 
internal::GetCpuThreadPool(),
                                         TaskHints hints = TaskHints{}) {
@@ -84,7 +84,7 @@ Status OptionalParallelFor(bool use_threads, int num_tasks, 
FUNCTION&& func,
 // depending on the input boolean.
 
 template <class FUNCTION, typename T,
-          typename R = typename 
internal::call_traits::return_type<FUNCTION>::ValueType>
+          typename R = typename std::invoke_result_t<FUNCTION, int, 
T>::ValueType>
 Future<std::vector<R>> OptionalParallelForAsync(
     bool use_threads, std::vector<T> inputs, FUNCTION&& func,
     Executor* executor = internal::GetCpuThreadPool(), TaskHints hints = 
TaskHints{}) {
diff --git a/cpp/src/arrow/util/vector.h b/cpp/src/arrow/util/vector.h
index 809497b9ae..ba979231ec 100644
--- a/cpp/src/arrow/util/vector.h
+++ b/cpp/src/arrow/util/vector.h
@@ -18,12 +18,12 @@
 #pragma once
 
 #include <algorithm>
+#include <type_traits>
 #include <utility>
 #include <vector>
 
 #include "arrow/result.h"
 #include "arrow/util/algorithm.h"
-#include "arrow/util/functional.h"
 #include "arrow/util/logging.h"
 
 namespace arrow {
@@ -106,8 +106,8 @@ std::vector<To> MapVector(Fn&& map, std::vector<From>&& 
source) {
 }
 
 /// \brief Like MapVector, but where the function can fail.
-template <typename Fn, typename From = internal::call_traits::argument_type<0, 
Fn>,
-          typename To = typename 
internal::call_traits::return_type<Fn>::ValueType>
+template <typename Fn, typename From,
+          typename To = typename std::invoke_result_t<Fn, From>::ValueType>
 Result<std::vector<To>> MaybeMapVector(Fn&& map, const std::vector<From>& 
source) {
   std::vector<To> out;
   out.reserve(source.size());
@@ -116,8 +116,8 @@ Result<std::vector<To>> MaybeMapVector(Fn&& map, const 
std::vector<From>& source
   return out;
 }
 
-template <typename Fn, typename From = internal::call_traits::argument_type<0, 
Fn>,
-          typename To = typename 
internal::call_traits::return_type<Fn>::ValueType>
+template <typename Fn, typename From,
+          typename To = typename std::invoke_result_t<Fn, From>::ValueType>
 Result<std::vector<To>> MaybeMapVector(Fn&& map, std::vector<From>&& source) {
   std::vector<To> out;
   out.reserve(source.size());
diff --git a/cpp/src/arrow/visit_data_inline.h 
b/cpp/src/arrow/visit_data_inline.h
index 3fa557af20..b7f08bdaee 100644
--- a/cpp/src/arrow/visit_data_inline.h
+++ b/cpp/src/arrow/visit_data_inline.h
@@ -18,6 +18,7 @@
 #pragma once
 
 #include <string_view>
+#include <type_traits>
 
 #include "arrow/array.h"
 #include "arrow/status.h"
@@ -27,7 +28,6 @@
 #include "arrow/util/bit_block_counter.h"
 #include "arrow/util/bit_util.h"
 #include "arrow/util/checked_cast.h"
-#include "arrow/util/functional.h"
 
 namespace arrow {
 namespace internal {
@@ -227,15 +227,21 @@ struct ArraySpanInlineVisitor<T, 
enable_if_fixed_size_binary<T>> {
 }  // namespace internal
 
 template <typename T, typename ValidFunc, typename NullFunc>
-typename internal::call_traits::enable_if_return<ValidFunc, Status>::type
-VisitArraySpanInline(const ArraySpan& arr, ValidFunc&& valid_func, NullFunc&& 
null_func) {
+  requires std::is_same_v<
+      std::invoke_result_t<ValidFunc,
+                           typename 
internal::ArraySpanInlineVisitor<T>::c_type>,
+      Status>
+Status VisitArraySpanInline(const ArraySpan& arr, ValidFunc&& valid_func,
+                            NullFunc&& null_func) {
   return internal::ArraySpanInlineVisitor<T>::VisitStatus(
       arr, std::forward<ValidFunc>(valid_func), 
std::forward<NullFunc>(null_func));
 }
 
 template <typename T, typename ValidFunc, typename NullFunc>
-typename internal::call_traits::enable_if_return<ValidFunc, void>::type
-VisitArraySpanInline(const ArraySpan& arr, ValidFunc&& valid_func, NullFunc&& 
null_func) {
+  requires std::is_void_v<std::invoke_result_t<
+      ValidFunc, typename internal::ArraySpanInlineVisitor<T>::c_type>>
+void VisitArraySpanInline(const ArraySpan& arr, ValidFunc&& valid_func,
+                          NullFunc&& null_func) {
   return internal::ArraySpanInlineVisitor<T>::VisitVoid(
       arr, std::forward<ValidFunc>(valid_func), 
std::forward<NullFunc>(null_func));
 }
@@ -274,10 +280,10 @@ struct ArraySpanVisitor {
 // The `NullFunc` should have the same return type as `ValidFunc`.
 
 template <typename ValidFunc, typename NullFunc>
-typename internal::call_traits::enable_if_return<ValidFunc, Status>::type
-VisitNullBitmapInline(const uint8_t* valid_bits, int64_t valid_bits_offset,
-                      int64_t num_values, int64_t null_count, ValidFunc&& 
valid_func,
-                      NullFunc&& null_func) {
+  requires std::is_same_v<std::invoke_result_t<ValidFunc>, Status>
+Status VisitNullBitmapInline(const uint8_t* valid_bits, int64_t 
valid_bits_offset,
+                             int64_t num_values, int64_t null_count,
+                             ValidFunc&& valid_func, NullFunc&& null_func) {
   internal::OptionalBitBlockCounter bit_counter(null_count == 0 ? NULLPTR : 
valid_bits,
                                                 valid_bits_offset, num_values);
   int64_t position = 0;
@@ -306,10 +312,10 @@ VisitNullBitmapInline(const uint8_t* valid_bits, int64_t 
valid_bits_offset,
 }
 
 template <typename ValidFunc, typename NullFunc>
-typename internal::call_traits::enable_if_return<ValidFunc, void>::type
-VisitNullBitmapInline(const uint8_t* valid_bits, int64_t valid_bits_offset,
-                      int64_t num_values, int64_t null_count, ValidFunc&& 
valid_func,
-                      NullFunc&& null_func) {
+  requires std::is_void_v<std::invoke_result_t<ValidFunc>>
+void VisitNullBitmapInline(const uint8_t* valid_bits, int64_t 
valid_bits_offset,
+                           int64_t num_values, int64_t null_count, ValidFunc&& 
valid_func,
+                           NullFunc&& null_func) {
   internal::OptionalBitBlockCounter bit_counter(null_count == 0 ? NULLPTR : 
valid_bits,
                                                 valid_bits_offset, num_values);
   int64_t position = 0;

Reply via email to