如何通过C++ 11 lambda中的move(也称为右值引用)捕获?
我想写这样的东西:
std::unique_ptr<int> myPointer(new int);
std::function<void(void)> example = [std::move(myPointer)]{
*myPointer = 4;
};
Run Code Online (Sandbox Code Playgroud) 我正在尝试创建std::function一个移动捕获lambda表达式.请注意,我可以创建一个移动捕获lambda表达式而不会出现问题; 只有当我尝试将其包装成一个std::function我得到错误时.
例如:
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);
Run Code Online (Sandbox Code Playgroud)
我会解释为什么我要写这样的东西.我写了一个UI库,类似于jQuery的或JavaFX的,允许用户通过传递给处理鼠标/键盘事件std::functions到方法有相似的名字on_mouse_down(),on_mouse_drag(),push_undo_action(),等.
显然,std::function我想要传入的理想情况下应该使用移动捕获lambda表达式,否则我需要求助于我在C++ 11作为标准时使用的丑陋的"release/acquire-in-lambda"习语:
std::function<void()> baz = …Run Code Online (Sandbox Code Playgroud) 因为std::function是可复制的,所以标准要求用于构造它的callables也是可复制的:
n337(20.8.11.2.1)
template<class F> function(F f);要求:
F应为CopyConstructible.f对于参数类型ArgTypes和返回类型,应为Callable(20.8.11.2)R.A的拷贝构造函数和析构函数不会抛出异常
这意味着不可能std::function从不可复制的绑定对象或捕获仅移动类型的lambda形成std::unique_ptr.
似乎可以为仅移动的callables实现这样一个仅移动的包装器.是否存在标准库仅限移动等效std::function或者,是否存在针对此问题的常见解决方法?
我最近尝试做这样的事情:
auto x = std::make_unique<int>(1);
auto l = [y = std::move(x)]() { return *y; };
std::function<void()> f(std::move(l)); //error, requires copy construction
Run Code Online (Sandbox Code Playgroud)
令我非常失望和困惑的是,它向我抛出了一堆错误消息。如您所知,std::function不允许从不可复制构造的类型进行构造。有什么具体原因吗?或者它是标准中的一个疏忽?仅移动类型的构造会带来什么问题?