如何从捕获移动的 lambda 表达式创建 std::function? [英] How to create an std::function from a move-capturing lambda expression?

查看:29
本文介绍了如何从捕获移动的 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::functions 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);

模板函数(allocator_arg_t, const A& a, F f);

要求: F 应该是 CopyConstructible.对于参数类型 ArgTypes 和返回类型 Rf 应该是 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功能&operator=(F&& f);

效果: function(std::forward(f)).swap(*this);

§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).

这篇关于如何从捕获移动的 lambda 表达式创建 std::function?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆