Move Capture in Lambdas
Question:
How do we implement move capture, also known as rvalue references, in C 11 lambdas? For instance:
std::unique_ptrmyPointer(new int); std::function example = [std::move(myPointer)] { *myPointer = 4; };
Answer:
Generalized Lambda Capture in C 14
In C 14, generalized lambda capture allows for move capture. This code is now valid:
using namespace std; auto u = make_unique(some, parameters); go.run([u = move(u)] { do_something_with(u); });
To move objects from a lambda to another function, make the lambda mutable:
go.run([u = move(u)] mutable { do_something_with(std::move(u)); });
Workaround for Move Capture in C 11
A helper function, make_rref, can facilitate move capture. Its implementation is as follows:
#include#include #include template struct rref_impl { rref_impl() = delete; rref_impl(T&& x) : x{std::move(x)} {} rref_impl(rref_impl& other) : x{std::move(other.x)}, isCopied{true} { assert(other.isCopied == false); } rref_impl(rref_impl&& other) : x{std::move(other.x)}, isCopied{std::move(other.isCopied)} { } rref_impl& operator=(rref_impl other) = delete; T& operator&&() { return std::move(x); } private: T x; bool isCopied = false; }; template rref_impl make_rref(T&& x) { return rref_impl {std::move(x)}; }
A test case for make_rref:
int main() { std::unique_ptrp{new int(0)}; auto rref = make_rref(std::move(p)); auto lambda = [rref]() mutable -> std::unique_ptr { return rref.move(); }; assert(lambda()); assert(!lambda()); }
Emulating Generalized Lambda Capture in C 11
Another workaround is provided by the capture() function:
#include#include int main() { std::unique_ptr p{new int(0)}; auto lambda = capture(std::move(p), [](std::unique_ptr & p) { return std::move(p); }); assert(lambda()); assert(!lambda()); }
capture is implemented as follows:
#includetemplate class capture_impl { T x; F f; public: capture_impl(T&& x, F&& f) : x{std::forward (x)}, f{std::forward (f)} {} template auto operator()(Ts&& ...args) -> decltype(f(x, std::forward (args)...)) { return f(x, std::forward (args)...); } template auto operator()(Ts&& ...args) const -> decltype(f(x, std::forward (args)...)) { return f(x, std::forward (args)...); } }; template capture_impl capture(T&& x, F&& f) { return capture_impl ( std::forward (x), std::forward (f)); }
This solution prevents copying the lambda if the captured type is not copyable, avoiding runtime errors.
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3