Moving local objects into lambda closure

104 views
Skip to first unread message

litb

unread,
Apr 14, 2009, 5:10:22 PM4/14/09
to
Hello List,

I've read the lambda wording and revised wording, but i haven't found
anything that makes the following common (i would think so) usage
valid:

function<void(std::string const&)> f() {
ostream os(....); // stands for a movable but not copyable
object
return [](std::string const& s) mutable { os << s; };
}

auto g = f; g("hello");

It looks to me as if the following fails if there is no publicly
accessible copy constructor. I would expect the above to move
construct a local data-member of the closure object from "os", which
would in effect make the lambda object non-copyable, but still
movable. But the specification says that it captures it by copy and
does not mention what happens in the above case.

Do i miss some detail about move construction of data-member?
If no, what were the rationale for disallowing the above?

--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

daniel....@googlemail.com

unread,
Apr 25, 2009, 6:11:33 PM4/25/09
to
On 14 Apr., 23:10, litb <Schaub-Johan...@web.de> wrote:
> I've read the lambda wording and revised wording, but i haven't found
> anything that makes the following common (i would think so) usage
> valid:
>
> function<void(std::string const&)> f() {
> ostream os(....); // stands for a movable but not copyable
> object
> return [](std::string const& s) mutable { os << s; };
> }
>
> auto g = f; g("hello");
>
> It looks to me as if the following fails if there is no publicly
> accessible copy constructor. I would expect the above to move
> construct a local data-member of the closure object from "os", which
> would in effect make the lambda object non-copyable, but still
> movable. But the specification says that it captures it by copy and
> does not mention what happens in the above case.
>
> Do i miss some detail about move construction of data-member?
> If no, what were the rationale for disallowing the above?

First the lambda expression is invalid, because it has an empty
capture set but attempts to use a variable of the next current
scope (os). As you have already recognized: It is currently not
possible to use "move-only" types as a captured variable.

While your use-case seems not unreasonable, I also think
that above syntax wouldn't be a good idea, because it does
completely hide the fact that the local os is moved! There
is no single std::move(os) or static_cast<ostream&&>(os)
in sight, which would break all the current syntactical
safety mechanisms provided by the rvalue proposal.

If we try to fix that the nearest syntactic equivalent that
comes to me in the moment would be something like:

function<void(std::string const&)> f() {
ostream os(....);

ostream&& ros = std::move(os);
return [&&ros](std::string const& s) mutable { ros << s; };
}

And some special rules must be added, because
ros is an lvalue and would without extra wording not
implicitly bind to ostream&& again.

Greetings from Bremen,

Daniel Krügler

avi.k...@googlemail.com

unread,
Feb 4, 2015, 2:20:08 PM2/4/15
to

On Sunday, April 26, 2009 at 1:11:33 AM UTC+3, daniel....@googlemail.com wrote:
>
> While your use-case seems not unreasonable, I also think
> that above syntax wouldn't be a good idea, because it does
> completely hide the fact that the local os is moved! There
> is no single std::move(os) or static_cast<ostream&&>(os)
> in sight, which would break all the current syntactical
> safety mechanisms provided by the rvalue proposal.
>
> If we try to fix that the nearest syntactic equivalent that
> comes to me in the moment would be something like:
>
> function<void(std::string const&)> f() {
> ostream os(....);
> ostream&& ros = std::move(os);
> return [&&ros](std::string const& s) mutable { ros << s; };
> }
>


I find myself writing tons of C++14 code moving objects into lambdas as in

[x = std::move(x)] (...) mutable {
...
}

It would be great if the syntax above could be standardized, so the
above would be:

[&&x] (...) {
...
}

(I propose making labmdas with move captured variables mutable by
default, to allow moving their objects out again, as this is a common
pattern with continuations.


--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp...@vandevoorde.com ]
Reply all
Reply to author
Forward
0 new messages