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

查看:142
本文介绍了如何从移动捕获lambda表达式创建std ::函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从移动捕获的lambda表达式创建一个std ::函数。注意,我可以创建一个移动捕获lambda表达式没有问题;只有当我试图将它包装在一个std ::函数,我得到一个错误。



例如:

  auto pi = std :: make_unique< int>(0); 

//这里没有问题!
auto foo = [q = std :: move(pi)] {
* q = 5;
std :: cout<< * q < std :: endl;
};

//下面的所有尝试都会产生:
//调用隐式删除的拷贝构造函数'< 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);

我会解释为什么我要写这样的东西。我写了一个UI库,类似于jQuery或JavaFX,允许用户处理鼠标/键盘事件通过传递std ::函数到名称像on_mouse_down(),on_mouse_drag(),push_undo_action()等的方法。 / p>

显然,我想传递的std ::函数应该理想地使用一个移动捕获lambda表达式,否则我需要诉诸丑陋的release / acquire- -lambdaidiom我使用时,C ++ 11是标准:

  std :: function< void()> baz = [q = pi.release()] {
std :: unique_ptr< int> p {q};
* p = 5;
std :: cout<< * q < std :: endl;
};

请注意,调用baz两次将是上述代码中的错误。但是,在我的代码中,这个闭包保证被调用一次。



BTW,在我的实际代码中,我不传递std :: unique_ptr int ,但更有趣的。



最后,我使用Xcode6-Beta4,它使用以下版本的clang:

  Apple LLVM版本5.1(clang-503.0.40)(基于LLVM 3.4svn)
目标:x86_64-apple-darwin13.3.0
线程模型: posix


解决方案


template< class F>函数(F f);



template< class F,class A&需要: 函数(allocator_arg_t,const A& a,F f);



< F
应为 CopyConstructible 。对于参数类型 ArgTypes 和返回类型, f 应为 Callable R 。 A的复制构造函数和析构函数不会抛出异常。



§20.9.11.2.1[func.wrap.func.con]


请注意, operator = 是根据此构造函数和 swap ,因此同样的限制适用:


template< class F>功能& operator =(F& f);



效果: :: forward(F))。swap(* this);



§20.9.11.2.1[func.wrap。 func.con]


所以回答你的问题:是的,可以构造一个 std ::函数从捕获移动的lambda(因为这只指定如何捕获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.

For example:

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);

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.

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;
};

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.

BTW, in my real code, I'm not passing an std::unique_ptr of int, but something more interesting.

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<class F> function(F f);

template <class F, class A> function(allocator_arg_t, const A& a, F f);

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]

Note that operator = is defined in terms of this constructor and swap, so the same restrictions apply:

template<class F> function& operator=(F&& f);

Effects: function(std::forward<F>(f)).swap(*this);

§20.9.11.2.1 [func.wrap.func.con]

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 ::函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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