This function, fed with any int
, returns a std::vector<int>
by value:
auto make = [](int){
return std::vector<int>{1,2,3};
};
Therefore, such a thing can't work
std::vector<int> v{1,2,3};
auto z = v | std::ranges::views::transform(make)
| std::ranges::views::join; // fails to compile
because, I understand (but correct me if I'm wrong), when the iterator wrapped in join
advances, it triggers the generations of the vectors by means of make
, but those temporary are already destroyed by the time the iterator in join
is dereferenced.
However, the following doesn't fail:
std::vector<int> v{1,2,3};
auto z = v | std::ranges::views::transform(boost::hana::always(make(int{})))
| std::ranges::views::join;
Why is that? What mechanism is being introduced by the use of always
?
I think the following is proof that both functions, make
and always(make(int{}))
, return a temporary. Am I making a mistake?
static_assert(!std::is_reference_v<decltype(make(int{}))>);
static_assert(!std::is_reference_v<decltype(boost::hana::always(make(int{}))(int{}))>);
There are two separate issues.
join_view
's restriction on joining ranges of prvalue ranges is a defect in C++20 that has been corrected by P2328R1. transform(make) | join
should Just Work on a standard library implementing the defect resolution (such as libstdc++ trunk).
hana::always
returns different things depending on whether it is invoked as an lvalue or rvalue. It returns an lvalue reference when invoked as an lvalue and a prvalue when invoked as an rvalue. transform
always invokes as lvalue, while your static_assert
is checking the result of invoking as rvalue.