Title
For `rank == 0`, `layout_stride` is atypically convertible
Status
new
Section
[mdspan.layout]
Submitter
Luc Grosheintz

Created on 2025-06-02.00:00:00 last changed 3 days ago

Messages

Date: 2025-06-28.12:53:59

Proposed resolution:

This wording is relative to N5008.

[Drafting note: As drive-by fixes the edits for layout_left_padded<>::mapping and layout_right_padded<>::mapping also correct an editorial asymmetry between class header synopsis declaration form and prototype specification form of the corresponding constructors and adjust to the correct formatting of the exposition-only data member rank_.]

  1. Modify [mdspan.layout.left.overview] as indicated:

    namespace std {
      template<class Extents>
      class layout_left::mapping {
        […]
        // [mdspan.layout.left.cons], constructors
        […]
        template<class OtherExtents>
          constexpr explicit(extents_type::rank() > 0see below)
            mapping(const layout_stride::mapping<OtherExtents>&);
        
        constexpr mapping& operator=(const mapping&) noexcept = default;
        […]
      };
    }
    
  2. Modify [mdspan.layout.left.cons] as indicated:

    template<class OtherExtents>
      constexpr explicit(extents_type::rank() > 0see below)
        mapping(const layout_stride::mapping<OtherExtents>& other);
    

    -13- Constraints: […]

    -14- Preconditions: […]

    -15- Effects: […]

    -?- Remarks: The expression inside `explicit` is equivalent to:

    !(extents_type::rank() == 0 && is_convertible_v<OtherExtents, extents_type>)
    
  3. Modify [mdspan.layout.right.overview] as indicated:

    namespace std {
      template<class Extents>
      class layout_right::mapping {
        […]
        // [mdspan.layout.right.cons], constructors
        […]
        template<class OtherExtents>
          constexpr explicit(extents_type::rank() > 0see below)
            mapping(const layout_stride::mapping<OtherExtents>&);
        
        constexpr mapping& operator=(const mapping&) noexcept = default;
        […]
      };
    }
    
  4. Modify [mdspan.layout.right.cons] as indicated:

    template<class OtherExtents>
      constexpr explicit(extents_type::rank() > 0see below)
        mapping(const layout_stride::mapping<OtherExtents>& other);
    

    -13- Constraints: […]

    -14- Preconditions: […]

    -15- Effects: […]

    -?- Remarks: The expression inside `explicit` is equivalent to:

    !(extents_type::rank() == 0 && is_convertible_v<OtherExtents, extents_type>)
    
  5. Modify [mdspan.layout.leftpad.overview] as indicated:

    namespace std {
      template<size_t PaddingValue>
      template<class Extents>
      class layout_left_padded<PaddingValue>::mapping {
        […]
        // [mdspan.layout.leftpad.cons], constructors
        […]
        template<class OtherExtents>
          constexpr explicit(extents_type::rank() > 0see below)
            mapping(const layout_stride::mapping<OtherExtents>&);
        […]
      };
    }
    
  6. Modify [mdspan.layout.leftpad.cons] as indicated:

    template<class OtherExtents>
      constexpr explicit(rank_ > 0see below)
        mapping(const layout_stride::mapping<OtherExtents>& other);
    

    -10- Constraints: […]

    -11- Preconditions: […]

    -12- Effects: […]

    -?- Remarks: The expression inside `explicit` is equivalent to:

    !(rank_ == 0 && is_convertible_v<OtherExtents, extents_type>)
    
    template<class LayoutLeftPaddedMapping>
      constexpr explicit(see below)
        mapping(const LayoutLeftPaddedMapping& other);
    

    -13- Constraints: […]

    […]

    -16- Remarks: The expression inside `explicit` is equivalent to:

    !is_convertible_v<typename LayoutLeftPaddedMapping::extents_type, extents_type> &&
    rank_> 1 &&
    (padding_value != dynamic_extent ||
     LayoutLeftPaddedMapping::padding_value == dynamic_extent)
    
  7. Modify [mdspan.layout.rightpad.overview] as indicated:

    namespace std {
      template<size_t PaddingValue>
      template<class Extents>
      class layout_right_padded<PaddingValue>::mapping {
        […]
        // [mdspan.layout.rightpad.cons], constructors
        […]
        template<class OtherExtents>
          constexpr explicit(rank_ > 0see below)
            mapping(const layout_stride::mapping<OtherExtents>&);
        […]
      };
    }
    
  8. Modify [mdspan.layout.rightpad.cons] as indicated:

    template<class OtherExtents>
      constexpr explicit(rank_ > 0see below)
        mapping(const layout_stride::mapping<OtherExtents>& other);
    

    -10- Constraints: […]

    -11- Preconditions: […]

    -12- Effects: […]

    -?- Remarks: The expression inside `explicit` is equivalent to:

    !(rank_ == 0 && is_convertible_v<OtherExtents, extents_type>)
    
    template<class LayoutRightPaddedMapping>
      constexpr explicit(see below)
        mapping(const LayoutRightPaddedMapping& other);
    

    -13- Constraints: […]

    […]

    -17- Remarks: The expression inside `explicit` is equivalent to:

    !is_convertible_v<typename LayoutRightPaddedMapping::extents_type, extents_type> &&
    rank_ > 1 &&
    (padding_value != dynamic_extent ||
    LayoutRightPaddedMapping::padding_value == dynamic_extent)
    
Date: 2025-06-15.00:00:00

[ 2025-06-20, Luc Grosheintz provides further wording improvements ]

Date: 2025-06-15.00:00:00

[ 2025-06-12; Reflector poll ]

Set priority to 2 after reflector poll.

This wording is relative to N5008.

[Drafting note: As drive-by fixes the edits for layout_left_padded<>::mapping and layout_right_padded<>::mapping also correct an editorial asymmetry between class header synopsis declaration form and prototype specification form of the corresponding constructors and adjust to the correct formatting of the exposition-only data member rank_.]

  1. Modify [mdspan.layout.left.overview] as indicated:

    namespace std {
      template<class Extents>
      class layout_left::mapping {
        […]
        // [mdspan.layout.left.cons], constructors
        […]
        template<class OtherExtents>
          constexpr explicit(extents_type::rank() > 0see below)
            mapping(const layout_stride::mapping<OtherExtents>&);
        
        constexpr mapping& operator=(const mapping&) noexcept = default;
        […]
      };
    }
    
  2. Modify [mdspan.layout.left.cons] as indicated:

    template<class OtherExtents>
      constexpr explicit(extents_type::rank() > 0see below)
        mapping(const layout_stride::mapping<OtherExtents>& other);
    

    -13- Constraints: […]

    -14- Preconditions: […]

    -15- Effects: […]

    -?- Remarks: The expression inside `explicit` is equivalent to:

    !(extents_type::rank() == 0 && is_convertible_v<OtherExtents, extents_type>)
    
  3. Modify [mdspan.layout.right.overview] as indicated:

    namespace std {
      template<class Extents>
      class layout_right::mapping {
        […]
        // [mdspan.layout.right.cons], constructors
        […]
        template<class OtherExtents>
          constexpr explicit(extents_type::rank() > 0see below)
            mapping(const layout_stride::mapping<OtherExtents>&);
        
        constexpr mapping& operator=(const mapping&) noexcept = default;
        […]
      };
    }
    
  4. Modify [mdspan.layout.right.cons] as indicated:

    template<class OtherExtents>
      constexpr explicit(extents_type::rank() > 0see below)
        mapping(const layout_stride::mapping<OtherExtents>& other);
    

    -13- Constraints: […]

    -14- Preconditions: […]

    -15- Effects: […]

    -?- Remarks: The expression inside `explicit` is equivalent to:

    !(extents_type::rank() == 0 && is_convertible_v<OtherExtents, extents_type>)
    
  5. Modify [mdspan.layout.leftpad.overview] as indicated:

    namespace std {
      template<size_t PaddingValue>
      template<class Extents>
      class layout_left_padded<PaddingValue>::mapping {
        […]
        // [mdspan.layout.leftpad.cons], constructors
        […]
        template<class OtherExtents>
          constexpr explicit(extents_type::rank() > 0see below)
            mapping(const layout_stride::mapping<OtherExtents>&);
        […]
      };
    }
    
  6. Modify [mdspan.layout.leftpad.cons] as indicated:

    template<class OtherExtents>
      constexpr explicit(rank_ > 0see below)
        mapping(const layout_stride::mapping<OtherExtents>& other);
    

    -10- Constraints: […]

    -11- Preconditions: […]

    -12- Effects: […]

    -?- Remarks: The expression inside `explicit` is equivalent to:

    !(rank_ == 0 && is_convertible_v<OtherExtents, extents_type>)
    
  7. Modify [mdspan.layout.rightpad.overview] as indicated:

    namespace std {
      template<size_t PaddingValue>
      template<class Extents>
      class layout_right_padded<PaddingValue>::mapping {
        […]
        // [mdspan.layout.rightpad.cons], constructors
        […]
        template<class OtherExtents>
          constexpr explicit(rank_ > 0see below)
            mapping(const layout_stride::mapping<OtherExtents>&);
        […]
      };
    }
    
  8. Modify [mdspan.layout.rightpad.cons] as indicated:

    template<class OtherExtents>
      constexpr explicit(rank_ > 0see below)
        mapping(const layout_stride::mapping<OtherExtents>& other);
    

    -10- Constraints: […]

    -11- Preconditions: […]

    -12- Effects: […]

    -?- Remarks: The expression inside `explicit` is equivalent to:

    !(rank_ == 0 && is_convertible_v<OtherExtents, extents_type>)
    
Date: 2025-06-14.09:46:28

Commonly, two layouts are considered convertible, if the underlying `extent_types` are convertible.

However, for the two ctors `layout_left::mapping(layout_stride::mapping)` and `layout_right::mapping(layout_stride::mapping)`, the condition is rank > 0. Therefore,

using E1 = std::extents<int>;
using E2 = std::extents<unsigned int>;

static_assert(std::is_convertible_v<
    std::layout_stride::mapping<E2>,
    std::layout_right::mapping<E1>
  >);

even though:

static_assert(!std::is_convertible_v<E2, E1>);

Moreover, for rank 0 `layout_stride` can be converted to any specialization of `layout_left` or `layout_right`; but not to every specialization of `layout_stride`.

History
Date User Action Args
2025-06-28 12:53:59adminsetmessages: + msg14867
2025-06-12 20:53:08adminsetmessages: + msg14798
2025-06-06 17:05:10adminsetmessages: + msg14779
2025-06-02 00:00:00admincreate