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

4171. P2609R3 breaks code that uses views::zip and get<T>

Section: 24.3.6.3 [indirectcallable.indirectinvocable] Status: Tentatively NAD Submitter: S. B. Tam Opened: 2024-11-01 Last modified: 2025-10-23

Priority: Not Prioritized

View all issues with Tentatively NAD status.

Discussion:

The following use of std::ranges::for_each is valid before P2609R3 and invalid after that.

#include <algorithm>
#include <ranges>
#include <tuple>
using namespace std::ranges;

void f() {
  int a[1];
  auto fun = [](auto t) {
    [[maybe_unused]] auto x = std::get<int&>(t);
  };
  for_each(views::zip(a), fun);
}

The reason is that, P2609R3 requires fun to be invocable with iter_value_t<I>&, which is tuple<int>& when I is zip_view's iterator, and tuple<int>& doesn't support std::get<int&>(t) because there isn't a int& member.

P2609R3 argues that "The actual consequence on user code seems small", but I believe that this code pattern is common enough, and it hurts if we cannot use get<int&>(t) in the lambda body.

Note that for_each doesn't actually call fun with iter_value_t<I>, as can be seen by adding an explicit return type to fun.

Did LWG foresee this impact of P2609R3? Could P2609R3 be reverted to unbreak this code pattern?

[2025-10-23; Reflector poll; Status changed: New → Tentatively NAD.]

The range concepts are over-constrained by design, and indirect_unary_invocable always required invocability with iter_value_t. The P2609 changes enforced this requirement properly for iterators returning proxy references, including zip_iterator.

Proposed resolution: