Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-05 09:19:20

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