range-v3 icon indicating copy to clipboard operation
range-v3 copied to clipboard

std::array | views::for_each | to_vector invokes lambda twice on each element

Open tom-huntington opened this issue 2 years ago • 4 comments

It doesn't do this for std::vector, or if we change for_each to transform. Annoying bug to troubleshoot if your invokable is not regular.

Heres a mcve https://godbolt.org/z/b5bv9fvrj

tom-huntington avatar Jul 30 '22 04:07 tom-huntington

Annoying bug to troubleshoot if your invokable is not regular.

Regular is a requirement on the invocable for transform and for_each.

brevzin avatar Jul 30 '22 13:07 brevzin

The specific reason for the change in behavior from array to vector:

auto in = std::array{1, 2, 3};
auto out = in | views::transform([](int i){ return std::vector{i}; } | views::join;

out here is actually still a sized_range in range-v3 (whereas it would not be if in were a vector<int>). The reason that out is still sized is that join provides a size for known-fixed-size ranges (range_cardinality<vector<int>> is finite but range_cardinality<array<int, 2>> is 2):

https://github.com/ericniebler/range-v3/blob/3d6e6f56e5e1a3ec4befcc7695504ea23e1d52ab/include/range/v3/view/join.hpp#L160-L172

When you then pipe that into to_vector, for sized ranges we use the size to allocate the correct amount - which in this case requires walking the underlying range (the transform_view) which requires invoking the function.

brevzin avatar Jul 30 '22 13:07 brevzin

Regular is a requirement on the invocable for transform and for_each.

Any observable behaviour will be depended upon ;).

Perhaps this line https://github.com/ericniebler/range-v3/blob/3d6e6f56e5e1a3ec4befcc7695504ea23e1d52ab/include/range/v3/view/join.hpp#L166 might be changed to

(range_cardinality<range_reference_t<Rng>>::value >= 0))

or added after.

tom-huntington avatar Jul 31 '22 05:07 tom-huntington

Regular is a requirement on the invocable for transform and for_each.

Any observable behaviour will be depended upon ;).

This isn't a Hyrum's Law thing, you're simply violating the preconditions of the algorithm.

brevzin avatar Jul 31 '22 22:07 brevzin