
Dave Abrahams wrote:
Side note:
* There is also a fully automatic approach (i.e. when an rvalue range is adapted, `moved_range` is automatically used without piping it to `moved` adaptor). But this approach incurs unnecessary overhead when passing them to functions, because function arguments do not have the lifetime issue and we don't need to use `moved_range`. So I prefer the "manual" approach.
Could you illustrate this with an example? I'd like to understand the trade-off you're making.
Here is an example of the manual approach:
template <typename Range> void f(Range&&);
// No lifetime problem. f(std::string("Hello world!") | reversed);
// `moved` is not necessary. f(std::string("Hello world!") | moved | reversed);
In the automatic approach, `std::string("Hello world!") | reversed` returns `moved_range<std::string, boost::fusion::vector<reverse_forwarder> >`.
As opposed to what? You haven't shown me what it returns in the manual approach.
In the manual approach it would return the same thing it does now: reversed_range<std::string>. Basically, the "automatic approach" is having every adaptor automatically wrap the range in a moved_range *just in case* it's used in a context where it needs to be moved, and the "manual approach" is having a "moved" adaptor that does the wrapping and needs to be used explicitly in such contexts, while leaving other adaptors unchanged. The tradeoff is between moving the container in contexts where it doesn't have to be moved (where the temporary range's lifetime is long enough) vs. having to remember to add " | moved" in contexts where it does have to be moved. Regards, Nate