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

4577. Hardening view_interface::operator[]

Section: 25.5.3 [view.interface] Status: Open Submitter: Hewill Kang Opened: 2026-05-11 Last modified: 2026-06-17

Priority: Not Prioritized

View other active issues in [view.interface].

View all other issues in [view.interface].

View all issues with Open status.

Discussion:

Hardening view_interface::operator[] to prevent out-of-bounds access is worthwhile for the sized_range cases, and we have already done so for other standard views such as span and string_view's operator[].

[2026-05-29 LWG telecon; status: New → Ready]

[2026-06-03; status: Ready → Open]

Reopen to bump the feature test macro.

Previous resolution [SUPERSEDED]

This wording is relative to N5046.

  1. Modify 25.5.3 [view.interface], class template view_interface synopsis, as indicated:

    namespace std::ranges {
      template<class D>
        requires is_class_v<D> && same_as<D, remove_cv_t<D>>
      class view_interface {
        […]
      public:
        […]
        template<random_access_range R = D>
          constexpr decltype(auto) operator[](range_difference_t<R> n) {
            return ranges::begin(derived())[n];
          };
        template<random_access_range R = const D>
          constexpr decltype(auto) operator[](range_difference_t<R> n) const {
            return ranges::begin(derived())[n];
          };
      };
    }
    
  2. Modify 25.5.3.2 [view.interface.members] as indicated:

    constexpr decltype(auto) back() requires bidirectional_range<D> && common_range<D>;
    constexpr decltype(auto) back() const
      requires bidirectional_range<const D> && common_range<const D>;
    

    -3- Hardened preconditions: !empty() is true.

    -4- Effects: Equivalent to: return *ranges::prev(ranges::end(derived()));

    
    template<random_access_range R = D>
      constexpr decltype(auto) operator[](range_difference_t<R> n);
    template<random_access_range R = const D>
      constexpr decltype(auto) operator[](range_difference_t<R> n) const;
    

    -?- Hardened preconditions: If D models sized_range, then n >= 0 && n < ranges::distance(derived()) is true.

    -?- Effects: Equivalent to: return ranges::begin(derived())[n];

[2026-06-03; Jonathan provides new wording]

[Brno 2026-06-08; Change status Open → Ready.]

Previous resolution [SUPERSEDED]

This wording is relative to N5046.

  1. Modify 17.3.2 [version.syn], Header <version> synopsis, as indicated:

    #define __cpp_lib_hardened_vector 202502L // also in <vector>
    #define __cpp_lib_hardened_view_interface 202506YYYYMML // also in <ranges>
    
  2. Modify 25.5.3 [view.interface], class template view_interface synopsis, as indicated:

    namespace std::ranges {
      template<class D>
        requires is_class_v<D> && same_as<D, remove_cv_t<D>>
      class view_interface {
        […]
      public:
        […]
        template<random_access_range R = D>
          constexpr decltype(auto) operator[](range_difference_t<R> n) {
            return ranges::begin(derived())[n];
          };
        template<random_access_range R = const D>
          constexpr decltype(auto) operator[](range_difference_t<R> n) const {
            return ranges::begin(derived())[n];
          };
      };
    }
    
  3. Modify 25.5.3.2 [view.interface.members] as indicated:

    constexpr decltype(auto) back() requires bidirectional_range<D> && common_range<D>;
    constexpr decltype(auto) back() const
      requires bidirectional_range<const D> && common_range<const D>;
    

    -3- Hardened preconditions: !empty() is true.

    -4- Effects: Equivalent to: return *ranges::prev(ranges::end(derived()));

    
    template<random_access_range R = D>
      constexpr decltype(auto) operator[](range_difference_t<R> n);
    template<random_access_range R = const D>
      constexpr decltype(auto) operator[](range_difference_t<R> n) const;
    

    -?- Hardened preconditions: If D models sized_range, then n >= 0 && n < ranges::distance(derived()) is true.

    -?- Effects: Equivalent to: return ranges::begin(derived())[n];

[2026-06-17; Change status Ready → Open; Jiang An comments and provides improved wording]

Consider the following program:

#include <ranges>

int main() 
{
  int a[2]{};
  std::ranges::subrange<int*> sr{a, a + 1};
  return sr[1]; // out of the bound of sr, but in the bound of the underlying range
}

Currently, the program has well-defined behavior, because the validity of the operator[] call is merely based on the reachable range of the stored iterator.

LWG 4577 introduces a hardened precondition for the operator[], which permits implementations to perform bound check and terminate the program if the index is incorrect for the subrange. However, the current (2026-06-03) proposed resolution will break some programs even on non-hardened implementations, by introducing UB that's not expected to be detected.

Perhaps we should restrict the precondition to hardened implementations, or some "partially hardened" implementations (which are not yet conforming though) hardening view_interface.

Proposed resolution:

This wording is relative to N5046.

  1. Modify 17.3.2 [version.syn], Header <version> synopsis, as indicated:

    #define __cpp_lib_hardened_vector 202502L // also in <vector>
    #define __cpp_lib_hardened_view_interface 202506YYYYMML // also in <ranges>
    
  2. Modify 25.5.3 [view.interface], class template view_interface synopsis, as indicated:

    namespace std::ranges {
      template<class D>
        requires is_class_v<D> && same_as<D, remove_cv_t<D>>
      class view_interface {
        […]
      public:
        […]
        template<random_access_range R = D>
          constexpr decltype(auto) operator[](range_difference_t<R> n) {
            return ranges::begin(derived())[n];
          };
        template<random_access_range R = const D>
          constexpr decltype(auto) operator[](range_difference_t<R> n) const {
            return ranges::begin(derived())[n];
          };
      };
    }
    
  3. Modify 25.5.3.2 [view.interface.members] as indicated:

    constexpr decltype(auto) back() requires bidirectional_range<D> && common_range<D>;
    constexpr decltype(auto) back() const
      requires bidirectional_range<const D> && common_range<const D>;
    

    -3- Hardened preconditions: !empty() is true.

    -4- Effects: Equivalent to: return *ranges::prev(ranges::end(derived()));

    
    template<random_access_range R = D>
      constexpr decltype(auto) operator[](range_difference_t<R> n);
    template<random_access_range R = const D>
      constexpr decltype(auto) operator[](range_difference_t<R> n) const;
    

    -?- Hardened preconditions: If the implementation defines __cpp_lib_hardened_view_interface and D models sized_range, then n >= 0 && n < ranges::distance(derived()) is true.

    -?- Effects: Equivalent to: return ranges::begin(derived())[n];