ORNL / cpp-proposals-pub

Collaborating on papers for the ISO C++ committee - public repo
26 stars 27 forks source link

A user-defined submdspan_mapping can return different mappings for the same kind of slice #475

Open mhoemmen opened 1 month ago

mhoemmen commented 1 month ago

The issue

A user-defined submdspan_mapping return different mappings for the same kind of slice. "Same kind of slice" means, for example, two different types that both model index-pair-like<index_type>.

This matters more given P2769R3 (get_element customization point object), which extends the definition of index-pair-like to include "anything for which get_element works." However, even the current definition of index-pair-like includes different Standard class templates, such as pair, tuple, array, and even complex. The following example shows a custom layout whose submdspan_mapping function returns a different layout mapping type, depending on whether the first slice is std::pair or some other index-pair-like type.

template<class T>
constexpr bool is_std_pair_v(T&&)
template<class First, class Second>
constexpr bool is_std_pair_v<std::pair<First, Second>> = true;

class custom_layout_1 {
  template<class Extents>
  class mapping { /* ... */ };
};

class custom_layout_2 {
  template<class Extents>
  class mapping { /* ... */ };
};

class custom_layout_3 {
  template<class Extents>
  class mapping {
    // ...
    template<class... SliceSpecifiers>
      friend constexpr auto submdspan_mapping(
        const mapping& src, SliceSpecifiers... slices) {
          using return_type = std::conditional_t<
            is_std_pair_v<std::remove_cvref_t<SliceSpecifiers...[0]>>,
            typename custom_layout_1::template mapping<Extents>;
            typename custom_layout_2::template mapping<Extents>
         >;
         return return_type{submdspan_extents(src.extents(), slices...)};
      } 
  };
};

Is this really a problem?

submdspan's wording (specifically, [mdspan.sub.sub] 5.2 and 5.3) implicitly describes the behavior of submdspan_mapping. It doesn't specify the return type of submdspan_mapping (other than to say it's a layout mapping with the same extents as submdspan_extents would have produced, given the input extents and slice specifiers). However, it does spell out the result mapping's extents() and the behavior of its operator(). The effect is that the result of submdspan views the expected subset of elements of the input mdspan, regardless of the type of the result's layout mapping.