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

### 3313. `join_view::iterator::operator--` is incorrectly constrained

Section: 24.7.12.3 [range.join.iterator] Status: C++20 Submitter: United States Opened: 2019-11-04 Last modified: 2021-02-25

Priority: 0

View all other issues in [range.join.iterator].

View all issues with C++20 status.

Discussion:

Addresses US 294

`join_view::iterator::operator--` is improperly constrained. In the Effects: clause in paragraph 14, we see the statement:

>     inner_ = ranges::end(*--outer_);

However, this only well-formed when `end` returns an iterator, not a sentinel. This requirement is not reflected in the constraints of the function(s).

Eric Niebler:

From the WD, `join_view::iterator::operator--` is specified as:

>     constexpr iterator& operator--()
>       requires ref_is_glvalue && bidirectional_range<Base> &&
>         bidirectional_range<range_reference_t<Base>>;

> -14- Effects: Equivalent to:

> >     if (outer_ == ranges::end(parent_->base_))
> >       inner_ = ranges::end(*--outer_);
> >     while (inner_ == ranges::begin(*outer_))
> >       inner_ = ranges::end(*--outer_);
> >     --inner_;
> >     return *this;

The trouble is from the lines that do:

>       inner_ = ranges::end(*--outer_);

Clearly this will only compile when `*--outer` returns a `common_range`, but nowhere is that requirement stated.

[2019-11 Status to Ready during Tuesday morning issue processing in Belfast.]

Proposed resolution:

This wording is relative to N4835.

1. Modify 24.7.12.3 [range.join.iterator], class template `join_view::iterator` synopsis, as indicated:

   >     constexpr iterator& operator--()
   >       requires ref_is_glvalue && bidirectional_range<Base> &&
   >                bidirectional_range<range_reference_t<Base>> &&
   >                common_range<range_reference_t<Base>>;

   >     constexpr iterator operator--(int)
   >       requires ref_is_glvalue && bidirectional_range<Base> &&
   >                bidirectional_range<range_reference_t<Base>> &&
   >                common_range<range_reference_t<Base>>;

2. Modify 24.7.12.3 [range.join.iterator] as indicated:

   >     constexpr iterator& operator--()
   >       requires ref_is_glvalue && bidirectional_range<Base> &&
   >                bidirectional_range<range_reference_t<Base>> &&
   >                common_range<range_reference_t<Base>>;

   > > -14- Effects: Equivalent to:

   > > >     if (outer_ == ranges::end(parent_->base_))
   > > >       inner_ = ranges::end(*--outer_);
   > > >     while (inner_ == ranges::begin(*outer_))
   > > >       inner_ = ranges::end(*--outer_);
   > > >     --inner_;
   > > >     return *this;

   >     constexpr iterator operator--(int)
   >       requires ref_is_glvalue && bidirectional_range<Base> &&
   >                bidirectional_range<range_reference_t<Base>> &&
   >                common_range<range_reference_t<Base>>;

   > > -15- Effects: Equivalent to:

   > > >     auto tmp = *this;
   > > >     --*this;
   > > >     return tmp;