This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
mdspan constructor should disallow derived to base conversionsSection: 23.7.3.6.2 [mdspan.mdspan.cons] Status: New Submitter: Hewill Kang Opened: 2025-10-05 Last modified: 2025-10-23
Priority: 3
View all issues with New status.
Discussion:
Unlike ranges::subrange or span, mdspan syntactically allows a multidimensional
viewing base class via a derived class pointer (demo):
#include <span>
#include <ranges>
#include <mdspan>
struct Base {};
struct Derived : Base {};
std::array<Derived, 12> arr;
std::ranges::subrange<Base*> s(arr); // error, slicing
std::span<Base> sp(arr.data(), arr.size()); // error, slicing
std::mdspan<Base, std::dims<1>> msp(arr.data(), arr.size()); // ok
Given that we intend to reject object slicing for both default_accessor and
aligned_accessor, there seems no reason not to reject this invalid pointer
arithmetic for mdspan.
[2025-10-23; Reflector poll.]
Set priority to 3 after reflector poll.
Even if data_handle_type is a pointer to value_type, this does not mean
that it points to contiguous range of value_type objects. Accessor may
provide different access parttern.
Proposed resolution:
This wording is relative to N5014.
[Drafting note: The exposition-only concept
convertible-to-non-slicingcomes from 25.5.4.1 [range.subrange.general].]
Modify 23.7.3.6.1 [mdspan.mdspan.overview] as indicated:
namespace std {
template<class ElementType, class Extents, class LayoutPolicy = layout_right,
class AccessorPolicy = default_accessor<ElementType>>
class mdspan {
public:
using extents_type = Extents;
using layout_type = LayoutPolicy;
using accessor_type = AccessorPolicy;
using mapping_type = typename layout_type::template mapping<extents_type>;
using element_type = ElementType;
using value_type = remove_cv_t<element_type>;
using index_type = typename extents_type::index_type;
using size_type = typename extents_type::size_type;
using rank_type = typename extents_type::rank_type;
using data_handle_type = typename accessor_type::data_handle_type;
using reference = typename accessor_type::reference;
[…]
template<class... OtherIndexTypes>
constexpr explicit mdspan(convertible-to-non-slicing<data_handle_type> auto ptr, OtherIndexTypes... exts);
template<class OtherIndexType, size_t N>
constexpr explicit(N != rank_dynamic())
mdspan(convertible-to-non-slicing<data_handle_type> auto p, span<OtherIndexType, N> exts);
template<class OtherIndexType, size_t N>
constexpr explicit(N != rank_dynamic())
mdspan(convertible-to-non-slicing<data_handle_type> auto p, const array<OtherIndexType, N>& exts);
constexpr mdspan(convertible-to-non-slicing<data_handle_type> auto p, const extents_type& ext);
constexpr mdspan(convertible-to-non-slicing<data_handle_type> auto p, const mapping_type& m);
constexpr mdspan(convertible-to-non-slicing<data_handle_type> auto p, const mapping_type& m, const accessor_type& a);
[…]
};
[…]
}
Modify 23.7.3.6.2 [mdspan.mdspan.cons] as indicated:
template<class... OtherIndexTypes> constexpr explicit mdspan(convertible-to-non-slicing<data_handle_type> auto p, OtherIndexTypes... exts);-4- Let
-5- Constraints: […] […]Nbesizeof...(OtherIndexTypes).template<class OtherIndexType, size_t N> constexpr explicit(N != rank_dynamic()) mdspan(convertible-to-non-slicing<data_handle_type> auto p, span<OtherIndexType, N> exts); template<class OtherIndexType, size_t N> constexpr explicit(N != rank_dynamic()) mdspan(convertible-to-non-slicing<data_handle_type> auto p, const array<OtherIndexType, N>& exts);-8- Constraints: […]
[…]constexpr mdspan(convertible-to-non-slicing<data_handle_type> auto p, const extents_type& ext);-11- Constraints: […]
[…]constexpr mdspan(convertible-to-non-slicing<data_handle_type> auto p, const mapping_type& m);-14- Constraints: […]
[…]constexpr mdspan(convertible-to-non-slicing<data_handle_type> auto p, const mapping_type& m, const accessor_type& a);-17- Preconditions: […]
[…]