如何从捕获移动的 lambda 表达式创建 std::function?
我正在尝试从捕获移动的 lambda 表达式创建一个 std::function
.请注意,我可以毫无问题地创建一个移动捕获 lambda 表达式;只有当我尝试将它包装在 std::function
中时,我才会收到错误.
I'm trying to create an std::function
from a move-capturing lambda expression. Note that I can create a move-capturing lambda expression without problems; it's only when I try to wrap it in an std::function
that I get an error.
例如:
auto pi = std::make_unique<int>(0);
// no problems here!
auto foo = [q = std::move(pi)] {
*q = 5;
std::cout << *q << std::endl;
};
// All of the attempts below yield:
// "Call to implicitly-deleted copy constructor of '<lambda...."
std::function<void()> bar = foo;
std::function<void()> bar{foo};
std::function<void()> bar{std::move(foo)};
std::function<void()> bar = std::move(foo);
std::function<void()> bar{std::forward<std::function<void()>>(foo)};
std::function<void()> bar = std::forward<std::function<void()>>(foo);
我会解释为什么我想写这样的东西.我编写了一个类似于 jQuery 或 JavaFX 的 UI 库,它允许用户通过将 std::function
传递给名称类似于 on_mouse_down()<的方法来处理鼠标/键盘事件/code>、
on_mouse_drag()
、push_undo_action()
等
I'll explain why I want to write something like this. I've written a UI library which, similar to jQuery or JavaFX, allows the user to handle mouse/keyboard events by passing std::function
s to methods with names like on_mouse_down()
, on_mouse_drag()
, push_undo_action()
, etc.
显然,我想传入的 std::function
理想情况下应该使用移动捕获 lambda 表达式,否则我需要诉诸丑陋的release/acquire-in-lambda"习语我在 C++11 是标准时使用:
Obviously, the std::function
I want to pass in should ideally use a move-capturing lambda expression, otherwise I need to resort to the ugly "release/acquire-in-lambda" idiom I was using when C++11 was the standard:
std::function<void()> baz = [q = pi.release()] {
std::unique_ptr<int> p{q};
*p = 5;
std::cout << *q << std::endl;
};
请注意,在上述代码中两次调用 baz
将是错误的.但是,在我的代码中,这个闭包保证只被调用一次.
Note that calling baz
twice would be an error in the above code. However, in my code, this closure is guaranteed to be called exactly once.
顺便说一句,在我的真实代码中,我没有传递 std::unique_ptr
,而是一些更有趣的东西.
BTW, in my real code, I'm not passing an std::unique_ptr<int>
, but something more interesting.
最后,我使用 Xcode6-Beta4,它使用以下版本的 clang:
Finally, I'm using Xcode6-Beta4 which uses the following version of clang:
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.3.0
Thread model: posix
推荐答案
template
函数(F f);
模板
要求: F
应该是 CopyConstructible
.对于参数类型 ArgTypes
和返回类型 R
,f
应该是 Callable
.A 的拷贝构造函数和析构函数不应抛出异常.
Requires: F
shall be CopyConstructible
. f
shall be Callable
for argument types ArgTypes
and return type R
. The copy constructor and destructor of A shall not throw exceptions.
§20.9.11.2.1 [func.wrap.func.con]
§20.9.11.2.1 [func.wrap.func.con]
注意operator =
是根据这个构造函数和swap
定义的,所以同样的限制适用:
Note that operator =
is defined in terms of this constructor and swap
, so the same restrictions apply:
template
效果: function(std::forward
§20.9.11.2.1 [func.wrap.func.con]
§20.9.11.2.1 [func.wrap.func.con]
所以要回答你的问题:是的,可以从移动捕获的 lambda 构造一个 std::function
(因为这仅指定了 lambda 捕获的方式),但它是 不可能从仅移动类型构造std::function
(例如移动捕获的lambda,它移动捕获不是复制的东西可施工).
So to answer your question: Yes, it is possible to construct a std::function
from a move-capturing lambda (since this only specifies how the lambda captures), but it is not possible to construct a std::function
from a move-only type (e.g. a move-capturing lambda which move-captures something that is not copy constructible).
相关文章