Range adaptor objects are underspecified
Tim Song

Created on 2020-12-15.00:00:00 last changed yesterday


Date: 2021-01-15.00:00:00

[ 2021-01-15; Telecon prioritization ]

Set priority to 2 following reflector and telecon discussions.

Date: 2020-12-15.00:00:00

There is implementation divergence in the handling of this example:

template<class F>
auto filter(F f) {
  return std::views::filter(f);
std::vector<int> v = {1, 2, 3, 4};
auto f = filter([i = std::vector{4}] (auto x) { return x == i[0]; });
auto x = v | f;

libstdc++'s views::filter stores a reference to the argument if it is passed as an lvalue, so f contains a dangling reference in the above example. MSVC's views::filter always stores a copy, and forwards that as either an lvalue or an rvalue depending on the range adaptor closure object's value category.

MSVC's behavior here seems desirable and is consistent with range-v3's behavior as well: the ability to form range adapter pipelines like this is an important feature, and there's nothing in the above example that even hints at a dangling reference problem.

However, the wording in [range.adaptor.object] is unclear at best about exactly how the arguments are stored in the adaptor(args...) case; arguably, the requirement that adaptor(range, args...) be equivalent to adaptor(args...)(range) may even rule out the ability to make an extra copy. Certainly nothing in the wording guarantees that it is safe to reuse lvalue range pipelines (that is, v | f doesn't move from f).

Date User Action Args
2021-01-15 21:45:23adminsetmessages: + msg11651
2020-12-15 00:00:00admincreate