[libcxx-commits] [libcxx] ab9f111 - [libcxx][span] Implement solution to LWG-3255

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu May 14 07:51:50 PDT 2020


Author: Michael Schellenberger Costa
Date: 2020-05-14T10:50:44-04:00
New Revision: ab9f11168f55add345f29592ec0946ac2e5ae697

URL: https://github.com/llvm/llvm-project/commit/ab9f11168f55add345f29592ec0946ac2e5ae697
DIFF: https://github.com/llvm/llvm-project/commit/ab9f11168f55add345f29592ec0946ac2e5ae697.diff

LOG: [libcxx][span] Implement solution to LWG-3255

This implements the relaxed requirements on the std::array constructors of span,
where the type only needs to be convertible to the element type of the span.

Note that the previous tests were not sufficient, as the const array<T, n> constructor
was only tested for compile time and the array<T, N> only during runtime.

Restructure the tests so that we can test conversions as well as both constructors.

Differential Revision: https://reviews.llvm.org/D75706

Added: 
    

Modified: 
    libcxx/include/span
    libcxx/test/std/containers/views/span.cons/stdarray.pass.cpp
    libcxx/www/cxx2a_status.html

Removed: 
    


################################################################################
diff  --git a/libcxx/include/span b/libcxx/include/span
index 1851ff3c0465..7ae0bdbd06b3 100644
--- a/libcxx/include/span
+++ b/libcxx/include/span
@@ -212,8 +212,16 @@ public:
         { (void)__l;     _LIBCPP_ASSERT(_Extent == distance(__f, __l), "size mismatch in span's constructor (ptr, ptr)"); }
 
     _LIBCPP_INLINE_VISIBILITY constexpr span(element_type (&__arr)[_Extent])          noexcept : __data{__arr} {}
-    _LIBCPP_INLINE_VISIBILITY constexpr span(      array<value_type, _Extent>& __arr) noexcept : __data{__arr.data()} {}
-    _LIBCPP_INLINE_VISIBILITY constexpr span(const array<value_type, _Extent>& __arr) noexcept : __data{__arr.data()} {}
+
+    template <class _OtherElementType,
+              enable_if_t<is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr>
+    _LIBCPP_INLINE_VISIBILITY
+    constexpr span(array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {}
+
+    template <class _OtherElementType,
+              enable_if_t<is_convertible_v<const _OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr>
+    _LIBCPP_INLINE_VISIBILITY
+    constexpr span(const array<_OtherElementType, _Extent>& __arr) noexcept : __data{__arr.data()} {}
 
     template <class _Container>
     _LIBCPP_INLINE_VISIBILITY
@@ -386,13 +394,15 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     constexpr span(element_type (&__arr)[_Sz])          noexcept : __data{__arr}, __size{_Sz} {}
 
-    template <size_t _Sz>
+    template <class _OtherElementType, size_t _Sz,
+              enable_if_t<is_convertible_v<_OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr>
     _LIBCPP_INLINE_VISIBILITY
-    constexpr span(array<value_type, _Sz>& __arr)       noexcept : __data{__arr.data()}, __size{_Sz} {}
+    constexpr span(array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {}
 
-    template <size_t _Sz>
+    template <class _OtherElementType, size_t _Sz,
+              enable_if_t<is_convertible_v<const _OtherElementType(*)[], element_type (*)[]>, nullptr_t> = nullptr>
     _LIBCPP_INLINE_VISIBILITY
-    constexpr span(const array<value_type, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {}
+    constexpr span(const array<_OtherElementType, _Sz>& __arr) noexcept : __data{__arr.data()}, __size{_Sz} {}
 
     template <class _Container>
     _LIBCPP_INLINE_VISIBILITY

diff  --git a/libcxx/test/std/containers/views/span.cons/stdarray.pass.cpp b/libcxx/test/std/containers/views/span.cons/stdarray.pass.cpp
index 88f46a889544..a59825310b66 100644
--- a/libcxx/test/std/containers/views/span.cons/stdarray.pass.cpp
+++ b/libcxx/test/std/containers/views/span.cons/stdarray.pass.cpp
@@ -68,49 +68,58 @@ void checkCV()
     }
 }
 
+template <typename T, typename U = T>
+constexpr bool testConstructorArray()
+{
+    std::array<U,2> val = { U(), U() };
+    ASSERT_NOEXCEPT(std::span<T>   {val});
+    ASSERT_NOEXCEPT(std::span<T, 2>{val});
+    std::span<T>    s1{val};
+    std::span<T, 2> s2{val};
+    return s1.data() == &val[0] && s1.size() == 2
+        && s2.data() == &val[0] && s2.size() == 2;
+}
 
-template <typename T>
-constexpr bool testConstexprSpan()
+template <typename T, typename U = T>
+constexpr bool testConstructorConstArray()
 {
-    constexpr std::array<T,2> val = { T(), T() };
+    const std::array<U,2> val = { U(), U() };
     ASSERT_NOEXCEPT(std::span<const T>   {val});
     ASSERT_NOEXCEPT(std::span<const T, 2>{val});
     std::span<const T>    s1{val};
     std::span<const T, 2> s2{val};
-    return
-        s1.data() == &val[0] && s1.size() == 2
-    &&  s2.data() == &val[0] && s2.size() == 2;
+    return s1.data() == &val[0] && s1.size() == 2
+        && s2.data() == &val[0] && s2.size() == 2;
 }
 
-
 template <typename T>
-void testRuntimeSpan()
-{
-    std::array<T,2> val;
-    ASSERT_NOEXCEPT(std::span<T>   {val});
-    ASSERT_NOEXCEPT(std::span<T, 2>{val});
-    std::span<T>    s1{val};
-    std::span<T, 2> s2{val};
-    assert(s1.data() == &val[0] && s1.size() == 2);
-    assert(s2.data() == &val[0] && s2.size() == 2);
+constexpr bool testConstructors() {
+    static_assert(testConstructorArray<T>(), "");
+    static_assert(testConstructorArray<const T, T>(), "");
+    static_assert(testConstructorConstArray<T>(), "");
+    static_assert(testConstructorConstArray<const T, T>(), "");
+
+    return testConstructorArray<T>()
+        && testConstructorArray<const T, T>()
+        && testConstructorConstArray<T>()
+        && testConstructorConstArray<const T, T>();
 }
 
 struct A{};
 
 int main(int, char**)
 {
-    static_assert(testConstexprSpan<int>(),    "");
-    static_assert(testConstexprSpan<long>(),   "");
-    static_assert(testConstexprSpan<double>(), "");
-    static_assert(testConstexprSpan<A>(),      "");
+    assert(testConstructors<int>());
+    assert(testConstructors<long>());
+    assert(testConstructors<double>());
+    assert(testConstructors<A>());
 
-    testRuntimeSpan<int>();
-    testRuntimeSpan<long>();
-    testRuntimeSpan<double>();
-    testRuntimeSpan<std::string>();
-    testRuntimeSpan<A>();
+    assert(testConstructors<int*>());
+    assert(testConstructors<int* const>());
+    assert(testConstructors<const int*>());
+    assert(testConstructors<const int* const>());
 
     checkCV();
 
-  return 0;
+    return 0;
 }

diff  --git a/libcxx/www/cxx2a_status.html b/libcxx/www/cxx2a_status.html
index 91b17f062006..2a0be14b3741 100644
--- a/libcxx/www/cxx2a_status.html
+++ b/libcxx/www/cxx2a_status.html
@@ -490,7 +490,7 @@ <h3>Library Working group Issues Status</h3>
 	<tr><td><a href="https://wg21.link/LWG3251">3251</a></td><td>Are <tt>std::format</tt> alignment specifiers applied to string arguments?</td><td>Prague</td><td></td></tr>
 	<tr><td><a href="https://wg21.link/LWG3252">3252</a></td><td>Parse locale's aware modifiers for commands are not consistent with POSIX spec</td><td>Prague</td><td></td></tr>
 	<tr><td><a href="https://wg21.link/LWG3254">3254</a></td><td>Strike <tt>stop_token</tt>'s <tt>operator!=</tt></td><td>Prague</td><td></td></tr>
-	<tr><td><a href="https://wg21.link/LWG3255">3255</a></td><td><tt>span</tt>'s <tt>array</tt> constructor is too strict</td><td>Prague</td><td></td></tr>
+	<tr><td><a href="https://wg21.link/LWG3255">3255</a></td><td><tt>span</tt>'s <tt>array</tt> constructor is too strict</td><td>Prague</td><td>Complete</td></tr>
 	<tr><td><a href="https://wg21.link/LWG3260">3260</a></td><td><tt>year_month*</tt> arithmetic rejects durations convertible to years</td><td>Prague</td><td></td></tr>
 	<tr><td><a href="https://wg21.link/LWG3262">3262</a></td><td>Formatting of negative durations is not specified</td><td>Prague</td><td></td></tr>
 	<tr><td><a href="https://wg21.link/LWG3264">3264</a></td><td><tt>sized_range</tt> and <tt>ranges::size</tt> redundantly use <tt>disable_sized_range</tt></td><td>Prague</td><td></td></tr>


        


More information about the libcxx-commits mailing list