From 02ca3b5fd52deb6e3c6238430f7048db03958cc0 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Mon, 2 Dec 2024 14:35:14 +0100 Subject: [PATCH] GH-44898: [C++] Fix compilation error on GCC 8 The `span` implementation featured a complicated SFINAE construct to enable the `span(range...)` constructor, which failed on compiling on gcc 8. Replace this complicated SFINAE with a much simpler one that avoids the recursive `span` template dependency while keeping the intended semantics. --- cpp/src/arrow/util/span.h | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/cpp/src/arrow/util/span.h b/cpp/src/arrow/util/span.h index 71cf9ed44890a..8a84d028b2ad8 100644 --- a/cpp/src/arrow/util/span.h +++ b/cpp/src/arrow/util/span.h @@ -28,28 +28,6 @@ namespace arrow::util { template class span; -// This trait is used to check if a type R can be used to construct a span. -// Specifically, it checks if std::data(R) and std::size(R) are valid expressions -// that may be passed to the span(T*, size_t) constructor. The reason this trait -// is needed rather than expressing this directly in the relevant span constructor -// is that this check requires instantiating span, which would violate the -// C++ standard if written directly in the constructor's enable_if clause -// because span is an incomplete type at that point. By defining this trait -// instead, we add an extra level of indirection that lets us delay the -// evaluation of the template until the first time the associated constructor -// is actually called, at which point span is a complete type. -// -// Note that most compilers do support the noncompliant construct, but nvcc -// does not. See https://github.com/apache/arrow/issues/40252 -template -struct ConstructibleFromDataAndSize : std::false_type {}; - -template -struct ConstructibleFromDataAndSize< - span, R, - std::void_t{std::data(std::declval()), - std::size(std::declval())})>> : std::true_type {}; - /// std::span polyfill. /// /// Does not support static extents. @@ -81,14 +59,12 @@ writing code which would break when it is replaced by std::span.)"); constexpr span(T* begin, T* end) : data_{begin}, size_{static_cast(end - begin)} {} - template < - typename R, - std::enable_if_t, R>::value, bool> = true, - typename DisableUnlessSimilarTypes = std::enable_if_t()))>>, - std::decay_t>>> + template ())), + typename RS = decltype(std::size(std::declval())), + typename E = std::enable_if_t && + std::is_constructible_v>> // NOLINTNEXTLINE runtime/explicit, non-const reference - constexpr span(R&& range) : span{std::data(range), std::size(range)} {} + constexpr span(R&& range) : data_{std::data(range)}, size_{std::size(range)} {} constexpr T* begin() const { return data_; } constexpr T* end() const { return data_ + size_; }