Title
P2609R3 breaks code that uses `views::zip` and get<T>
Status
nad
Section
[indirectcallable.indirectinvocable]
Submitter
S. B. Tam

Created on 2024-11-01.00:00:00 last changed yesterday

Messages

Date: 2025-12-10.00:00:00

[ 2025-12-10 Status changed: Tentatively NAD → NAD. ]

Date: 2025-10-15.00:00:00

[ 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`.

Date: 2024-11-01.00:00:00

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?

History
Date User Action Args
2025-12-10 23:00:58adminsetmessages: + msg15800
2025-10-23 09:34:52adminsetmessages: + msg15368
2025-10-23 09:34:52adminsetstatus: new -> nad
2024-11-01 00:00:00admincreate