Issue 4272: For rank == 0, layout_stride is atypically convertible (original) (raw)


This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

4272. For rank == 0, layout_stride is atypically convertible

Section: 23.7.3.4 [mdspan.layout] Status: WP Submitter: Luc Grosheintz Opened: 2025-06-02 Last modified: 2025-11-11

Priority: 2

View all other issues in [mdspan.layout].

View all issues with WP status.

Discussion:

Commonly, two layouts are considered convertible, if the underlyingextent_types are convertible.

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

using E1 = std::extents; using E2 = std::extents;

static_assert(std::is_convertible_v< std::layout_stride::mapping, std::layout_right::mapping

);

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.

[2025-06-12; Reflector poll]

Set priority to 2 after reflector poll.

Previous resolution [SUPERSEDED]:

This wording is relative to N5008.

[Drafting note: As drive-by fixes the edits for layout_left_padded<>::mapping andlayout_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 23.7.3.4.5.1 [mdspan.layout.left.overview] as indicated:

    namespace std {
    template
    class layout_left::mapping {
    […]
    // 23.7.3.4.5.2 [mdspan.layout.left.cons], constructors
    […]
    template
    constexpr explicit(extents_type::rank() > 0see below)

   mapping(const layout_stride::mapping<OtherExtents>&);  

constexpr mapping& operator=(const mapping&) noexcept = default;
[…]
};
} 2. Modify 23.7.3.4.5.2 [mdspan.layout.left.cons] as indicated:
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping& 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 23.7.3.4.6.1 [mdspan.layout.right.overview] as indicated:
namespace std {
template
class layout_right::mapping {
[…]
// 23.7.3.4.6.2 [mdspan.layout.right.cons], constructors
[…]
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping&);

constexpr mapping& operator=(const mapping&) noexcept = default;
[…]
};
} 4. Modify 23.7.3.4.6.2 [mdspan.layout.right.cons] as indicated:
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping& 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 23.7.3.4.8.1 [mdspan.layout.leftpad.overview] as indicated:
namespace std {
template
template
class layout_left_padded::mapping {
[…]
// 23.7.3.4.8.3 [mdspan.layout.leftpad.cons], constructors
[…]
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping&);
[…]
};
} 6. Modify 23.7.3.4.8.3 [mdspan.layout.leftpad.cons] as indicated:
template
constexpr explicit(rank_ > 0see below)
mapping(const layout_stride::mapping& 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 23.7.3.4.9.1 [mdspan.layout.rightpad.overview] as indicated:
namespace std {
template
template
class layout_right_padded::mapping {
[…]
// 23.7.3.4.9.3 [mdspan.layout.rightpad.cons], constructors
[…]
template
constexpr explicit(rank_ > 0see below)
mapping(const layout_stride::mapping&);
[…]
};
} 8. Modify 23.7.3.4.9.3 [mdspan.layout.rightpad.cons] as indicated:
template
constexpr explicit(rank_ > 0see below)
mapping(const layout_stride::mapping& other);

-10- Constraints: […]

-11- Preconditions: […]

-12- Effects: […]

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

!(rank == 0 && is_convertible_v<OtherExtents, extents_type>)

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

Previous resolution [SUPERSEDED]:

This wording is relative to N5008.

[Drafting note: As drive-by fixes the edits for layout_left_padded<>::mapping andlayout_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 23.7.3.4.5.1 [mdspan.layout.left.overview] as indicated:

    namespace std {
    template
    class layout_left::mapping {
    […]
    // 23.7.3.4.5.2 [mdspan.layout.left.cons], constructors
    […]
    template
    constexpr explicit(extents_type::rank() > 0see below)

   mapping(const layout_stride::mapping<OtherExtents>&);  

constexpr mapping& operator=(const mapping&) noexcept = default;
[…]
};
} 2. Modify 23.7.3.4.5.2 [mdspan.layout.left.cons] as indicated:
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping& 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 23.7.3.4.6.1 [mdspan.layout.right.overview] as indicated:
namespace std {
template
class layout_right::mapping {
[…]
// 23.7.3.4.6.2 [mdspan.layout.right.cons], constructors
[…]
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping&);

constexpr mapping& operator=(const mapping&) noexcept = default;
[…]
};
} 4. Modify 23.7.3.4.6.2 [mdspan.layout.right.cons] as indicated:
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping& 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 23.7.3.4.8.1 [mdspan.layout.leftpad.overview] as indicated:
namespace std {
template
template
class layout_left_padded::mapping {
[…]
// 23.7.3.4.8.3 [mdspan.layout.leftpad.cons], constructors
[…]
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping&);
[…]
};
} 6. Modify 23.7.3.4.8.3 [mdspan.layout.leftpad.cons] as indicated:
template
constexpr explicit(rank_ > 0see below)
mapping(const layout_stride::mapping& other);

-10- Constraints: […]

-11- Preconditions: […]

-12- Effects: […]

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

!(rank == 0 && is_convertible_v<OtherExtents, extents_type>)

template
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 23.7.3.4.9.1 [mdspan.layout.rightpad.overview] as indicated:
namespace std {
template
template
class layout_right_padded::mapping {
[…]
// 23.7.3.4.9.3 [mdspan.layout.rightpad.cons], constructors
[…]
template
constexpr explicit(rank_ > 0see below)
mapping(const layout_stride::mapping&);
[…]
};
} 8. Modify 23.7.3.4.9.3 [mdspan.layout.rightpad.cons] as indicated:
template
constexpr explicit(rank_ > 0see below)
mapping(const layout_stride::mapping& other);

-10- Constraints: […]

-11- Preconditions: […]

-12- Effects: […]

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

!(rank == 0 && is_convertible_v<OtherExtents, extents_type>)

template
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)

[2025-09-27, Tomasz Kamiński fixes constraints in constructors from padded layouts]

[Kona 2025-11-05; approved by LWG. Status changed: New → Immediate.]

[Kona 2025-11-08; Status changed: Immediate → WP.]

Proposed resolution:

This wording is relative to N5008.

[Drafting note: As drive-by fixes the edits for layout_left_padded<>::mapping andlayout_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 23.7.3.4.5.1 [mdspan.layout.left.overview] as indicated:

    namespace std {
    template
    class layout_left::mapping {
    […]
    // 23.7.3.4.5.2 [mdspan.layout.left.cons], constructors
    […]
    template
    constexpr explicit(extents_type::rank() > 0see below)

   mapping(const layout_stride::mapping<OtherExtents>&);  

constexpr mapping& operator=(const mapping&) noexcept = default;
[…]
};
} 2. Modify 23.7.3.4.5.2 [mdspan.layout.left.cons] as indicated:
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping& 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 23.7.3.4.6.1 [mdspan.layout.right.overview] as indicated:
namespace std {
template
class layout_right::mapping {
[…]
// 23.7.3.4.6.2 [mdspan.layout.right.cons], constructors
[…]
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping&);

constexpr mapping& operator=(const mapping&) noexcept = default;
[…]
};
} 4. Modify 23.7.3.4.6.2 [mdspan.layout.right.cons] as indicated:
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping& 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 23.7.3.4.8.1 [mdspan.layout.leftpad.overview] as indicated:
namespace std {
template
template
class layout_left_padded::mapping {
[…]
// 23.7.3.4.8.3 [mdspan.layout.leftpad.cons], constructors
[…]
template
constexpr explicit(extents_type::rank() > 0see below)
mapping(const layout_stride::mapping&);
[…]
};
} 6. Modify 23.7.3.4.8.3 [mdspan.layout.leftpad.cons] as indicated:
template
constexpr explicit(rank_ > 0see below)
mapping(const layout_stride::mapping& other);

-10- Constraints: […]

-11- Preconditions: […]

-12- Effects: […]

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

!(rank == 0 && is_convertible_v<OtherExtents, extents_type>)

template
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 23.7.3.4.9.1 [mdspan.layout.rightpad.overview] as indicated:
namespace std {
template
template
class layout_right_padded::mapping {
[…]
// 23.7.3.4.9.3 [mdspan.layout.rightpad.cons], constructors
[…]
template
constexpr explicit(rank_ > 0see below)
mapping(const layout_stride::mapping&);
[…]
};
} 8. Modify 23.7.3.4.9.3 [mdspan.layout.rightpad.cons] as indicated:
template
constexpr explicit(rank_ > 0see below)
mapping(const layout_stride::mapping& other);

-10- Constraints: […]

-11- Preconditions: […]

-12- Effects: […]

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

!(rank == 0 && is_convertible_v<OtherExtents, extents_type>)

template
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)