QSpan: add construction from initializer_list
P2447 has been merged in C++26, backport the same functionality. This makes QSpan<const T> a proper replacement for a const QList<T>& parameter, because now both can be built via a braced-init-list. // void f(const QList<int> &l); // old void f(QSpan<const int>); // new f({1, 2, 3}); // now OK This is, technically speaking, SiC: in the presence of both `f` overloads, the code above would have called the QList one. Now instead the call is ambiguous. We've been there already -- this is QString and QStringView all over again, and the solution is the same: get rid of the owning container overload. I'd rather have this construction *sooner* rather than *later* in order to minimize the fallout. And just like QString vs QStringView, there's nothing really doable to prevent instant-dangling situations: QStringView v = getString(); // dangles QSpan<const int> s = {1, 2, 3}; // ditto except for using QSpan (QStringView) as a *parameter type only*. Note that QSpan with dynamic extent was already convertible from std::initializer_list through its ranged constructor. However this fact alone doesn't unlock the above syntax. QSpan with a static extent was also convertible for the same reason. (This is non-standard: std::span's range constructor for static extents is explicit, but QSpan doesn't follow that design choice and makes the constructors implicit instead.) Found in API-review. Change-Id: I160ab5b292b0c2568cd9a7ad1b4430085f475c29 Reviewed-by: Marc Mutz <marc.mutz@qt.io> (cherry picked from commit 7f7b5ff3a1b617a3a1add1b1b6ad0718f0dcf143) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
9ea3087d36
commit
c80f475055
@ -11,6 +11,7 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <QtCore/q20iterator.h>
|
||||
#include <QtCore/q20memory.h>
|
||||
#ifdef __cpp_lib_span
|
||||
@ -224,6 +225,11 @@ public:
|
||||
: QSpanBase(other.data(), other.size())
|
||||
{}
|
||||
|
||||
template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
|
||||
Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il)
|
||||
: QSpanBase(il.begin(), il.size())
|
||||
{}
|
||||
|
||||
#ifdef __cpp_lib_span
|
||||
template <typename S, if_qualification_conversion<S> = true>
|
||||
Q_IMPLICIT constexpr QSpanBase(std::span<S, E> other) noexcept
|
||||
@ -286,6 +292,11 @@ public:
|
||||
: QSpanBase(other.data(), other.size())
|
||||
{}
|
||||
|
||||
template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
|
||||
Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il) noexcept
|
||||
: QSpanBase(il.begin(), il.size())
|
||||
{}
|
||||
|
||||
#if __cpp_lib_span
|
||||
template <typename S, size_t N, if_qualification_conversion<S> = true>
|
||||
Q_IMPLICIT constexpr QSpanBase(std::span<S, N> other) noexcept
|
||||
@ -347,6 +358,7 @@ public:
|
||||
template <typename Range, if_compatible_range<Range> = true> constexpr QSpan(Range &&r);
|
||||
template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(QSpan<S, N> other) noexcept;
|
||||
template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::span<S, N> other) noexcept;
|
||||
constexpr QSpan(std::initializer_list<value_type> il);
|
||||
#endif // Q_QDOC
|
||||
|
||||
// [span.obs]
|
||||
|
@ -341,6 +341,18 @@
|
||||
\endlist
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T, size_t E> QSpan<T, E>::QSpan(std::initializer_list<value_type> il);
|
||||
|
||||
Constructs a QSpan referencing the data in the supplied initializer list \a il.
|
||||
|
||||
\note This constructor participates in overload resolution only if \c{T} is \c{const}-qualified.
|
||||
|
||||
\note This constructor is \c{noexcept} only if \c{E} is \c{std::dynamic_extent}.
|
||||
|
||||
\note If \c{E} is not \c{std::dynamic_extent} and the size of \a il is not \c{E}, the behavior is undefined.
|
||||
*/
|
||||
|
||||
//
|
||||
// Member functions: sizes
|
||||
//
|
||||
|
@ -99,6 +99,15 @@ static_assert(!std::is_convertible_v<QSpan<const int, 0>, std::span<int, 0>>);
|
||||
// Spans don't convert from nonsense:
|
||||
static_assert(!std::is_constructible_v<QSpan<const int>, int&&>);
|
||||
|
||||
// Span is constructible from initializer_list
|
||||
static_assert( std::is_convertible_v<std::initializer_list<int>, QSpan<const int>>);
|
||||
static_assert(!std::is_convertible_v<std::initializer_list<int>, QSpan< int>>);
|
||||
static_assert(!std::is_constructible_v<QSpan<int>, std::initializer_list<int>>);
|
||||
|
||||
static_assert( std::is_convertible_v<std::initializer_list<int>, QSpan<const int, 4>>); // non-standard, but QSpan considers initializer_list a range
|
||||
static_assert( std::is_constructible_v<QSpan<const int, 4>, std::initializer_list<int>>);
|
||||
static_assert(!std::is_constructible_v<QSpan< int, 4>, std::initializer_list<int>>);
|
||||
|
||||
class tst_QSpan : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -114,6 +123,7 @@ private Q_SLOTS:
|
||||
void fromZeroSizeStdArray() const;
|
||||
void fromStdVector() const;
|
||||
void fromQList() const;
|
||||
void fromInitList() const;
|
||||
|
||||
private:
|
||||
template <typename T, std::size_t N>
|
||||
@ -322,9 +332,11 @@ void tst_QSpan::from_container_impl(C &&c) const
|
||||
{
|
||||
const auto c_size = qsizetype(QSpanPrivate::adl_size(c));
|
||||
const auto c_data = QSpanPrivate::adl_data(c);
|
||||
|
||||
using V = std::remove_reference_t<QSpanPrivate::range_reference_t<C>>;
|
||||
{
|
||||
QSpan si = c; // CTAD
|
||||
static_assert(std::is_same_v<decltype(si), QSpan<int, ExpectedExtent>>);
|
||||
static_assert(std::is_same_v<decltype(si), QSpan<V, ExpectedExtent>>);
|
||||
|
||||
QCOMPARE_EQ(si.size(), c_size);
|
||||
QCOMPARE_EQ(si.data(), c_data);
|
||||
@ -421,6 +433,17 @@ void tst_QSpan::fromQList() const
|
||||
from_variable_size_container_impl(li);
|
||||
}
|
||||
|
||||
void tst_QSpan::fromInitList() const
|
||||
{
|
||||
from_variable_size_container_impl(std::initializer_list<int>{42, 84, 168, 336});
|
||||
|
||||
auto l1 = [](QSpan<const int>){};
|
||||
l1({1, 2, 3});
|
||||
|
||||
auto l2 = [](QSpan<const int, 3>){};
|
||||
l2({4, 5, 6});
|
||||
}
|
||||
|
||||
#undef RETURN_IF_FAILED
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QSpan);
|
||||
|
Loading…
x
Reference in New Issue
Block a user