Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 09:04:38

0001 // Copyright (C) 2023 The Qt Company Ltd.
0002 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
0003 
0004 #ifndef QSPAN_H
0005 #define QSPAN_H
0006 
0007 #include <QtCore/qcompilerdetection.h>
0008 #include <QtCore/qtypes.h>
0009 #include <QtCore/qcontainerfwd.h>
0010 
0011 #include <array>
0012 #include <cstddef>
0013 #include <cassert>
0014 #include <initializer_list>
0015 #include <QtCore/q20iterator.h>
0016 #include <QtCore/q20memory.h>
0017 #ifdef __cpp_lib_span
0018 #include <span>
0019 #endif
0020 #include <QtCore/q20type_traits.h>
0021 
0022 QT_BEGIN_NAMESPACE
0023 
0024 // like std::dynamic_extent
0025 namespace q20 {
0026     inline constexpr auto dynamic_extent = std::size_t(-1);
0027 } // namespace q20
0028 
0029 QT_BEGIN_INCLUDE_NAMESPACE
0030 #ifdef __cpp_lib_span
0031 #ifdef __cpp_lib_concepts
0032 namespace std::ranges {
0033 // Officially, these are defined in <ranges>, but that is a heavy-hitter header.
0034 // OTOH, <span> must specialize these variable templates, too, so we assume that
0035 // <span> includes some meaningful subset of <ranges> and just go ahead and use them:
0036 template <typename T, std::size_t E>
0037 constexpr inline bool enable_borrowed_range<QT_PREPEND_NAMESPACE(QSpan)<T, E>> = true;
0038 template <typename T, std::size_t E>
0039 constexpr inline bool enable_view<QT_PREPEND_NAMESPACE(QSpan)<T, E>> = true;
0040 } // namespace std::ranges
0041 #endif // __cpp_lib_concepts
0042 #endif // __cpp_lib_span
0043 QT_END_INCLUDE_NAMESPACE
0044 
0045 namespace QSpanPrivate {
0046 
0047 template <typename From, typename To>
0048 std::conditional_t<std::is_const_v<From>, const To &, To &> // like [forward]/6.1 COPY_CONST
0049 const_propagated(To &in) { return in; }
0050 
0051 template <typename T, std::size_t E> class QSpanBase;
0052 
0053 template <typename T>
0054 struct is_qspan_helper : std::false_type {};
0055 template <typename T, std::size_t E>
0056 struct is_qspan_helper<QSpan<T, E>> : std::true_type {};
0057 template <typename T, std::size_t E>
0058 struct is_qspan_helper<QSpanBase<T, E>> : std::true_type {};
0059 template <typename T>
0060 using is_qspan = is_qspan_helper<q20::remove_cvref_t<T>>;
0061 
0062 template <typename T>
0063 struct is_std_span_helper : std::false_type {};
0064 #ifdef __cpp_lib_span
0065 template <typename T, std::size_t E>
0066 struct is_std_span_helper<std::span<T, E>> : std::true_type {};
0067 #endif // __cpp_lib_span
0068 template <typename T>
0069 using is_std_span = is_std_span_helper<q20::remove_cvref_t<T>>;
0070 
0071 template <typename T>
0072 struct is_std_array_helper : std::false_type {};
0073 template <typename T, std::size_t N>
0074 struct is_std_array_helper<std::array<T, N>> : std::true_type {};
0075 template <typename T>
0076 using is_std_array = is_std_array_helper<q20::remove_cvref_t<T>>;
0077 
0078 template <typename From, typename To>
0079 using is_qualification_conversion =
0080     std::is_convertible<From(*)[], To(*)[]>; // https://eel.is/c++draft/span.cons#note-1
0081 template <typename From, typename To>
0082 constexpr inline bool is_qualification_conversion_v = is_qualification_conversion<From, To>::value;
0083 
0084 namespace AdlTester {
0085 #define MAKE_ADL_TEST(what) \
0086     using std:: what; /* bring into scope */ \
0087     template <typename T> using what ## _result = decltype( what (std::declval<T&&>())); \
0088     /* end */
0089 MAKE_ADL_TEST(begin)
0090 MAKE_ADL_TEST(data)
0091 MAKE_ADL_TEST(size)
0092 #undef MAKE_ADL_TEST
0093 }
0094 
0095 // Replacements for std::ranges::XXX(), but only bringing in ADL XXX()s,
0096 // not doing the extra work C++20 requires
0097 template <typename Range>
0098 AdlTester::begin_result<Range> adl_begin(Range &&r) { using std::begin; return begin(r); }
0099 template <typename Range>
0100 AdlTester::data_result<Range>  adl_data(Range &&r)  { using std::data; return data(r); }
0101 template <typename Range>
0102 AdlTester::size_result<Range>  adl_size(Range &&r)  { using std::size; return size(r); }
0103 
0104 // Replacement for std::ranges::iterator_t (which depends on C++20 std::ranges::begin)
0105 // This one uses adl_begin() instead.
0106 template <typename Range>
0107 using iterator_t = decltype(QSpanPrivate::adl_begin(std::declval<Range&>()));
0108 template <typename Range>
0109 using range_reference_t = q20::iter_reference_t<QSpanPrivate::iterator_t<Range>>;
0110 
0111 template <typename T>
0112 class QSpanCommon {
0113 protected:
0114     template <typename Iterator>
0115     using is_compatible_iterator = std::conjunction<
0116             // ### C++20: extend to contiguous_iteratorss
0117             std::is_base_of<
0118                 std::random_access_iterator_tag,
0119                 typename std::iterator_traits<Iterator>::iterator_category
0120             >,
0121             is_qualification_conversion<
0122                 std::remove_reference_t<q20::iter_reference_t<Iterator>>,
0123                 T
0124             >
0125         >;
0126     template <typename Iterator, typename End>
0127     using is_compatible_iterator_and_sentinel = std::conjunction<
0128             // ### C++20: extend to contiguous_iterators and real sentinels
0129             is_compatible_iterator<Iterator>,
0130             std::negation<std::is_convertible<End, std::size_t>>
0131         >;
0132     template <typename Range, typename = void> // wrap use of SFINAE-unfriendly iterator_t:
0133     struct is_compatible_range_helper : std::false_type {};
0134     template <typename Range>
0135     struct is_compatible_range_helper<Range, std::void_t<QSpanPrivate::iterator_t<Range>>>
0136         : is_compatible_iterator<QSpanPrivate::iterator_t<Range>> {};
0137     template <typename Range>
0138     using is_compatible_range = std::conjunction<
0139             // ### C++20: extend to contiguous_iterators
0140             std::negation<is_qspan<Range>>,
0141             std::negation<is_std_span<Range>>,
0142             std::negation<is_std_array<Range>>,
0143             std::negation<std::is_array<q20::remove_cvref_t<Range>>>,
0144             is_compatible_range_helper<Range>
0145         >;
0146 
0147     // constraints
0148     template <typename Iterator>
0149     using if_compatible_iterator = std::enable_if_t<
0150                 is_compatible_iterator<Iterator>::value
0151             , bool>;
0152     template <typename Iterator, typename End>
0153     using if_compatible_iterator_and_sentinel = std::enable_if_t<
0154                 is_compatible_iterator_and_sentinel<Iterator, End>::value
0155             , bool>;
0156     template <typename Range>
0157     using if_compatible_range = std::enable_if_t<is_compatible_range<Range>::value, bool>;
0158 }; // class QSpanCommon
0159 
0160 template <typename T, std::size_t E>
0161 class QSpanBase : protected QSpanCommon<T>
0162 {
0163     static_assert(E < size_t{(std::numeric_limits<qsizetype>::max)()},
0164                   "QSpan only supports extents that fit into the signed size type (qsizetype).");
0165 
0166     template <typename S, std::size_t N>
0167     using if_compatible_array = std::enable_if_t<
0168             N == E && is_qualification_conversion_v<S, T>
0169         , bool>;
0170 
0171     template <typename S>
0172     using if_qualification_conversion = std::enable_if_t<
0173             is_qualification_conversion_v<S, T>
0174         , bool>;
0175 protected:
0176     using Base = QSpanCommon<T>;
0177 
0178     // data members:
0179     T *m_data;
0180     static constexpr qsizetype m_size = qsizetype(E);
0181 
0182     // types and constants:
0183     // (in QSpan only)
0184 
0185     // constructors (need to be public d/t the way ctor inheriting works):
0186 public:
0187     template <std::size_t E2 = E, std::enable_if_t<E2 == 0, bool> = true>
0188     Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr} {}
0189 
0190     template <typename It, typename Base::template if_compatible_iterator<It> = true>
0191     explicit constexpr QSpanBase(It first, qsizetype count)
0192         : m_data{q20::to_address(first)}
0193     {
0194         Q_ASSERT(count == m_size);
0195     }
0196 
0197     template <typename It, typename End, typename Base::template if_compatible_iterator_and_sentinel<It, End> = true>
0198     explicit constexpr QSpanBase(It first, End last)
0199         : QSpanBase(first, last - first) {}
0200 
0201     template <size_t N, std::enable_if_t<N == E, bool> = true>
0202     Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t<T> (&arr)[N]) noexcept
0203         : QSpanBase(arr, N) {}
0204 
0205     template <typename S, size_t N, if_compatible_array<S, N> = true>
0206     Q_IMPLICIT constexpr QSpanBase(std::array<S, N> &arr) noexcept
0207         : QSpanBase(arr.data(), N) {}
0208 
0209     template <typename S, size_t N, if_compatible_array<S, N> = true>
0210     Q_IMPLICIT constexpr QSpanBase(const std::array<S, N> &arr) noexcept
0211         : QSpanBase(arr.data(), N) {}
0212 
0213     template <typename Range, typename Base::template if_compatible_range<Range> = true>
0214     Q_IMPLICIT constexpr QSpanBase(Range &&r)
0215         : QSpanBase(QSpanPrivate::adl_data(QSpanPrivate::const_propagated<T>(r)), // no forward<>() here (std doesn't have it, either)
0216                     qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>()
0217     {}
0218 
0219     template <typename S, if_qualification_conversion<S> = true>
0220     Q_IMPLICIT constexpr QSpanBase(QSpan<S, E> other) noexcept
0221         : QSpanBase(other.data(), other.size())
0222     {}
0223 
0224     template <typename S, if_qualification_conversion<S> = true>
0225     Q_IMPLICIT constexpr QSpanBase(QSpan<S> other)
0226         : QSpanBase(other.data(), other.size())
0227     {}
0228 
0229     template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
0230     Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il)
0231         : QSpanBase(il.begin(), il.size())
0232     {}
0233 
0234 #ifdef __cpp_lib_span
0235     template <typename S, if_qualification_conversion<S> = true>
0236     Q_IMPLICIT constexpr QSpanBase(std::span<S, E> other) noexcept
0237         : QSpanBase(other.data(), other.size())
0238     {}
0239 
0240     template <typename S, if_qualification_conversion<S> = true>
0241     Q_IMPLICIT constexpr QSpanBase(std::span<S> other)
0242         : QSpanBase(other.data(), other.size())
0243     {}
0244 #endif // __cpp_lib_span
0245 }; // class QSpanBase (fixed extent)
0246 
0247 template <typename T>
0248 class QSpanBase<T, q20::dynamic_extent> : protected QSpanCommon<T>
0249 {
0250     template <typename S>
0251     using if_qualification_conversion = std::enable_if_t<
0252             is_qualification_conversion_v<S, T>
0253         , bool>;
0254 protected:
0255     using Base = QSpanCommon<T>;
0256 
0257     // data members:
0258     T *m_data;
0259     qsizetype m_size;
0260 
0261     // constructors (need to be public d/t the way ctor inheriting works):
0262 public:
0263     Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr}, m_size{0} {}
0264 
0265     template <typename It, typename Base::template if_compatible_iterator<It> = true>
0266     Q_IMPLICIT constexpr QSpanBase(It first, qsizetype count)
0267         : m_data{q20::to_address(first)}, m_size{count} {}
0268 
0269     template <typename It, typename End, typename Base::template if_compatible_iterator_and_sentinel<It, End> = true>
0270     Q_IMPLICIT constexpr QSpanBase(It first, End last)
0271         : QSpanBase(first, last - first) {}
0272 
0273     template <size_t N>
0274     Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t<T> (&arr)[N]) noexcept
0275         : QSpanBase(arr, N) {}
0276 
0277     template <typename S, size_t N, if_qualification_conversion<S> = true>
0278     Q_IMPLICIT constexpr QSpanBase(std::array<S, N> &arr) noexcept
0279         : QSpanBase(arr.data(), N) {}
0280 
0281     template <typename S, size_t N, if_qualification_conversion<S> = true>
0282     Q_IMPLICIT constexpr QSpanBase(const std::array<S, N> &arr) noexcept
0283         : QSpanBase(arr.data(), N) {}
0284 
0285     template <typename Range, typename Base::template if_compatible_range<Range> = true>
0286     Q_IMPLICIT constexpr QSpanBase(Range &&r)
0287         : QSpanBase(QSpanPrivate::adl_data(QSpanPrivate::const_propagated<T>(r)), // no forward<>() here (std doesn't have it, either)
0288                     qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>()
0289     {}
0290 
0291     template <typename S, size_t N, if_qualification_conversion<S> = true>
0292     Q_IMPLICIT constexpr QSpanBase(QSpan<S, N> other) noexcept
0293         : QSpanBase(other.data(), other.size())
0294     {}
0295 
0296     template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
0297     Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il) noexcept
0298         : QSpanBase(il.begin(), il.size())
0299     {}
0300 
0301 #ifdef __cpp_lib_span
0302     template <typename S, size_t N, if_qualification_conversion<S> = true>
0303     Q_IMPLICIT constexpr QSpanBase(std::span<S, N> other) noexcept
0304         : QSpanBase(other.data(), other.size())
0305     {}
0306 #endif // __cpp_lib_span
0307 }; // class QSpanBase (dynamic extent)
0308 
0309 } // namespace QSpanPrivate
0310 
0311 template <typename T, std::size_t E>
0312 class QSpan
0313 #ifndef Q_QDOC
0314     : private QSpanPrivate::QSpanBase<T, E>
0315 #endif
0316 {
0317     using Base = QSpanPrivate::QSpanBase<T, E>;
0318     Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
0319                                           [[maybe_unused]] qsizetype n = 1) const
0320     {
0321         Q_ASSERT(pos >= 0);
0322         Q_ASSERT(pos <= size());
0323         Q_ASSERT(n >= 0);
0324         Q_ASSERT(n <= size() - pos);
0325     }
0326 
0327     template <std::size_t N>
0328     static constexpr bool subspan_always_succeeds_v = N <= E && E != q20::dynamic_extent;
0329 public:
0330     // constants and types
0331     using value_type = std::remove_cv_t<T>;
0332 #ifdef QT_COMPILER_HAS_LWG3346
0333     using iterator_concept = std::contiguous_iterator_tag;
0334     using element_type = T;
0335 #endif
0336     using size_type = qsizetype;               // difference to std::span
0337     using difference_type = qptrdiff;          // difference to std::span
0338     using pointer = T*;
0339     using const_pointer = const T*;
0340     using reference = T&;
0341     using const_reference = const T&;
0342     using iterator = pointer;                  // implementation-defined choice
0343     using const_iterator = const_pointer;      // implementation-defined choice
0344     using reverse_iterator = std::reverse_iterator<iterator>;
0345     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0346     static constexpr std::size_t extent = E;
0347 
0348     // [span.cons], constructors, copy, and assignment
0349     using Base::Base;
0350 #ifdef Q_QDOC
0351     template <typename It> using if_compatible_iterator = bool;
0352     template <typename S> using if_qualification_conversion = bool;
0353     template <typename Range> using if_compatible_range = bool;
0354     template <typename It, if_compatible_iterator<It> = true> constexpr QSpan(It first, qsizetype count);
0355     template <typename It, if_compatible_iterator<It> = true> constexpr QSpan(It first, It last);
0356     template <size_t N> constexpr QSpan(q20::type_identity_t<T> (&arr)[N]) noexcept;
0357     template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::array<S, N> &arr) noexcept;
0358     template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(const std::array<S, N> &arr) noexcept;
0359     template <typename Range, if_compatible_range<Range> = true> constexpr QSpan(Range &&r);
0360     template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(QSpan<S, N> other) noexcept;
0361     template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::span<S, N> other) noexcept;
0362     constexpr QSpan(std::initializer_list<value_type> il);
0363 #endif // Q_QDOC
0364 
0365     // [span.obs]
0366     [[nodiscard]] constexpr size_type size() const noexcept { return this->m_size; }
0367     [[nodiscard]] constexpr size_type size_bytes() const noexcept { return size() * sizeof(T); }
0368     [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
0369 
0370     // [span.elem]
0371     [[nodiscard]] constexpr reference operator[](size_type idx) const
0372     { verify(idx); return data()[idx]; }
0373     [[nodiscard]] constexpr reference front() const { verify(); return *data(); }
0374     [[nodiscard]] constexpr reference back() const  { verify(); return data()[size() - 1]; }
0375     [[nodiscard]] constexpr pointer data() const noexcept { return this->m_data; }
0376 
0377     // [span.iterators]
0378     [[nodiscard]] constexpr iterator begin() const noexcept { return data(); }
0379     [[nodiscard]] constexpr iterator end() const noexcept { return data() + size(); }
0380     [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return begin(); }
0381     [[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); }
0382     [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
0383     [[nodiscard]] constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
0384     [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
0385     [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); }
0386 
0387     // [span.sub]
0388     template <std::size_t Count>
0389     [[nodiscard]] constexpr QSpan<T, Count> first() const
0390         noexcept(subspan_always_succeeds_v<Count>)
0391     {
0392         static_assert(Count <= E,
0393                       "Count cannot be larger than the span's extent.");
0394         verify(0, Count);
0395         return QSpan<T, Count>{data(), Count};
0396     }
0397 
0398     template <std::size_t Count>
0399     [[nodiscard]] constexpr QSpan<T, Count> last() const
0400         noexcept(subspan_always_succeeds_v<Count>)
0401     {
0402         static_assert(Count <= E,
0403                       "Count cannot be larger than the span's extent.");
0404         verify(0, Count);
0405         return QSpan<T, Count>{data() + (size() - Count), Count};
0406     }
0407 
0408     template <std::size_t Offset>
0409     [[nodiscard]] constexpr auto subspan() const
0410         noexcept(subspan_always_succeeds_v<Offset>)
0411     {
0412         static_assert(Offset <= E,
0413                       "Offset cannot be larger than the span's extent.");
0414         verify(Offset, 0);
0415         if constexpr (E == q20::dynamic_extent)
0416             return QSpan<T>{data() + Offset, qsizetype(size() - Offset)};
0417         else
0418             return QSpan<T, E - Offset>{data() + Offset, qsizetype(E - Offset)};
0419     }
0420 
0421     template <std::size_t Offset, std::size_t Count>
0422     [[nodiscard]] constexpr auto subspan() const
0423         noexcept(subspan_always_succeeds_v<Offset + Count>)
0424     { return subspan<Offset>().template first<Count>(); }
0425 
0426     [[nodiscard]] constexpr QSpan<T> first(size_type n) const { verify(0, n); return {data(), n}; }
0427     [[nodiscard]] constexpr QSpan<T> last(size_type n)  const { verify(0, n); return {data() + (size() - n), n}; }
0428     [[nodiscard]] constexpr QSpan<T> subspan(size_type pos) const { verify(pos, 0); return {data() + pos, size() - pos}; }
0429     [[nodiscard]] constexpr QSpan<T> subspan(size_type pos, size_type n) const { return subspan(pos).first(n); }
0430 
0431     // Qt-compatibility API:
0432     [[nodiscard]] constexpr bool isEmpty() const noexcept { return empty(); }
0433     // nullary first()/last() clash with first<>() and last<>(), so they're not provided for QSpan
0434     [[nodiscard]] constexpr QSpan<T> sliced(size_type pos) const { return subspan(pos); }
0435     [[nodiscard]] constexpr QSpan<T> sliced(size_type pos, size_type n) const { return subspan(pos, n); }
0436     [[nodiscard]] constexpr QSpan<T> chopped(size_type n) const { verify(0, n); return first(size() - n); }
0437 
0438 #ifdef __cpp_concepts
0439 #  define QT_ONLY_IF_DYNAMIC_SPAN(DECL) \
0440     DECL requires(E == q20::dynamic_extent)
0441 #else
0442 #  define QT_ONLY_IF_DYNAMIC_SPAN(DECL) \
0443     template <size_t M = E, typename = std::enable_if_t<M == q20::dynamic_extent>> DECL
0444 #endif
0445     QT_ONLY_IF_DYNAMIC_SPAN(
0446     constexpr void slice(size_type pos)
0447     )
0448     { *this = sliced(pos); }
0449     QT_ONLY_IF_DYNAMIC_SPAN(
0450     constexpr void slice(size_type pos, size_type n)
0451     )
0452     { *this = sliced(pos, n); }
0453     QT_ONLY_IF_DYNAMIC_SPAN(
0454     constexpr void chop(size_type n)
0455     )
0456     { *this = chopped(n); }
0457 #undef QT_ONLY_IF_DYNAMIC_SPAN
0458 
0459 private:
0460     // [span.objectrep]
0461     [[nodiscard]] friend
0462     QSpan<const std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>
0463     as_bytes(QSpan s) noexcept
0464     {
0465         using R = QSpan<const std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>;
0466         return R{reinterpret_cast<const std::byte *>(s.data()), s.size_bytes()};
0467     }
0468 
0469     template <typename U>
0470     using if_mutable = std::enable_if_t<!std::is_const_v<U>, bool>;
0471 
0472 #ifndef Q_QDOC
0473     template <typename T2 = T, if_mutable<T2> = true>
0474 #endif
0475     [[nodiscard]] friend
0476     QSpan<std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>
0477     as_writable_bytes(QSpan s) noexcept
0478     {
0479         using R = QSpan<std::byte, E == q20::dynamic_extent ? q20::dynamic_extent : E * sizeof(T)>;
0480         return R{reinterpret_cast<std::byte *>(s.data()), s.size_bytes()};
0481     }
0482 }; // class QSpan
0483 
0484 // [span.deduct]
0485 template <class It, class EndOrSize>
0486 QSpan(It, EndOrSize) -> QSpan<std::remove_reference_t<q20::iter_reference_t<It>>>;
0487 template <class T, std::size_t N>
0488 QSpan(T (&)[N]) -> QSpan<T, N>;
0489 template <class T, std::size_t N>
0490 QSpan(std::array<T, N> &) -> QSpan<T, N>;
0491 template <class T, std::size_t N>
0492 QSpan(const std::array<T, N> &) -> QSpan<const T, N>;
0493 template <class R>
0494 QSpan(R&&) -> QSpan<std::remove_reference_t<QSpanPrivate::range_reference_t<R>>>;
0495 
0496 QT_END_NAMESPACE
0497 
0498 #endif // QSPAN_H