3864. zip over range of reference to an abstract type

Section: 25.7.25 [range.zip] Status: New Submitter: Barry Revzin Opened: 2023-01-28 Last modified: 2023-02-06

Priority: 4

View all issues with New status.

Discussion:

Consider:

#include <ranges>

struct Abstract {
  virtual ~Abstract() = default;
  virtual int f() = 0;
};

struct Concrete : Abstract {
  int f() override { return 42; }
};

int main() {
  Concrete c[10];

  auto xformed = c | std::views::transform([](Concrete& c) -> Abstract& {
    return c;
  });

  for (Abstract& a : xformed) { }  // ok

  auto zipped = std::views::zip(xformed);

  for (auto&& [a] : zipped) { }    // error
}

Here, xformed is a range whose reference type is Abstract& and whose value_type is Abstract. Even though you can't actually create a value of that value_type, that's okay here, because no code is actually trying to do so.

On the other hand, zipped is a range whose reference type is std::tuple<Abstract&> and whose value_type is std::tuple<Abstract>. No code here is actually trying to construct a value_type either, but this code fails because simply instantiating std::tuple<Abstract> is an error. There's no other possible value_type for zipped to have, std::tuple<Abstract> is correct — it's just that it happens to be an ill-formed type in this context. There are workarounds for this case — you would have to make xformed be a range of Abstract* or, probably better, a range of reference_wrapper<Abstract> instead.

This is unfortunate because many (most?) algorithms don't actually make any use of a range's value_type. The ones that do (like ranges::min) obviously could not work, but currently we end up rejecting all uses. Probably the only possible way to make this work is to allow value_type to be void (or absent), but it is currently a fairly fundamental type due to its use in indirectly_readable to identify input iterators.

[2023-02-06; Reflector poll]

Set priority to 4 after reflector poll. Several votes for NAD. Maybe tuple<Abstract> should be explicitly made ill-formed (currently seems underspecified) or should be "disabled" like invalid hash specializations and formatters.

Proposed resolution: