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;