移动 lambda:一旦你移动捕获了一个只能移动的类型,如何使用 lambda?
Moving a lambda: once you've move-captured a move-only type, how can the lambda be used?
This answer 解释了如何在 C++14 中的 lambda 中移动捕获变量。
但是一旦您在 lambda 中移动捕获了一个不可复制的对象(例如 std::unique_ptr
),您将无法复制 lambda 本身。
如果您可以移动 lambda 就好了,但是我在尝试这样做时遇到编译错误:
using namespace std;
class HasCallback
{
public:
void setCallback(std::function<void(void)>&& f)
{
callback = move(f);
}
std::function<void(void)> callback;
};
int main()
{
auto uniq = make_unique<std::string>("Blah blah blah");
HasCallback hc;
hc.setCallback(
[uniq = move(uniq)](void)
{
std::cout << *uniq << std::endl;
});
hc.callback();
}
g++
会产生以下错误(我试图只复制相关行):
error: use of deleted function ‘main()::<lambda()>::<lambda>(const main()::<lambda()>&’
...暗示,我认为,我尝试移动 lambda 失败了。
clang++
给出了类似的错误。
我明确地尝试 move
ing lambda(即使它是一个临时值),但这没有帮助。
编辑: 下面的答案充分解决了上述代码产生的编译错误。对于替代方法,只需 release
唯一指针的目标值到 std::shared_ptr
中, 可以 复制。 (我不是把它写成一个答案,因为那会假设这是一个 XY 问题,但是 unique_ptr
不能在转换为 std::function
的 lambda 中使用的根本原因理解很重要。)
编辑 2: 够搞笑的,我刚刚意识到 auto_ptr
实际上会在这里做正确的事(!),据我所知。它的行为本质上类似于 unique_ptr
,但允许复制构造代替移动构造。
您可以移动 lambda,没关系。不过,这不是您的问题所在,您正在尝试使用不可复制的 lambda 实例化 std::function
。还有:
template< class F >
function( F f );
function
的构造函数:
5) Initializes the target with a copy of f
.
这是因为std::function
:
satisfies the requirements of CopyConstructible and CopyAssignable.
由于function
必须是可复制的,所以你放入其中的所有内容也必须是可复制的。而仅移动的 lambda 不满足该要求。
std::function
不是 lambda!它是一个包装器,可以从任何类型的可调用对象构造,包括 lambda。 std::function
要求 callable be copy-constructible,这就是您的示例失败的原因。
只能移动的 lambda 可以再次移动,如下所示。
template<typename F>
void call(F&& f)
{
auto f1 = std::forward<F>(f); // construct a local copy
f1();
}
int main()
{
auto uniq = make_unique<std::string>("Blah blah blah");
auto lambda = [uniq = move(uniq)]() {
std::cout << *uniq << std::endl;
};
// call(lambda); // doesn't compile because the lambda cannot be copied
call(std::move(lambda));
}
This answer 解释了如何在 C++14 中的 lambda 中移动捕获变量。
但是一旦您在 lambda 中移动捕获了一个不可复制的对象(例如 std::unique_ptr
),您将无法复制 lambda 本身。
如果您可以移动 lambda 就好了,但是我在尝试这样做时遇到编译错误:
using namespace std;
class HasCallback
{
public:
void setCallback(std::function<void(void)>&& f)
{
callback = move(f);
}
std::function<void(void)> callback;
};
int main()
{
auto uniq = make_unique<std::string>("Blah blah blah");
HasCallback hc;
hc.setCallback(
[uniq = move(uniq)](void)
{
std::cout << *uniq << std::endl;
});
hc.callback();
}
g++
会产生以下错误(我试图只复制相关行):
error: use of deleted function ‘main()::<lambda()>::<lambda>(const main()::<lambda()>&’
...暗示,我认为,我尝试移动 lambda 失败了。
clang++
给出了类似的错误。
我明确地尝试 move
ing lambda(即使它是一个临时值),但这没有帮助。
编辑: 下面的答案充分解决了上述代码产生的编译错误。对于替代方法,只需 release
唯一指针的目标值到 std::shared_ptr
中, 可以 复制。 (我不是把它写成一个答案,因为那会假设这是一个 XY 问题,但是 unique_ptr
不能在转换为 std::function
的 lambda 中使用的根本原因理解很重要。)
编辑 2: 够搞笑的,我刚刚意识到 auto_ptr
实际上会在这里做正确的事(!),据我所知。它的行为本质上类似于 unique_ptr
,但允许复制构造代替移动构造。
您可以移动 lambda,没关系。不过,这不是您的问题所在,您正在尝试使用不可复制的 lambda 实例化 std::function
。还有:
template< class F >
function( F f );
function
的构造函数:
5) Initializes the target with a copy of
f
.
这是因为std::function
:
satisfies the requirements of CopyConstructible and CopyAssignable.
由于function
必须是可复制的,所以你放入其中的所有内容也必须是可复制的。而仅移动的 lambda 不满足该要求。
std::function
不是 lambda!它是一个包装器,可以从任何类型的可调用对象构造,包括 lambda。 std::function
要求 callable be copy-constructible,这就是您的示例失败的原因。
只能移动的 lambda 可以再次移动,如下所示。
template<typename F>
void call(F&& f)
{
auto f1 = std::forward<F>(f); // construct a local copy
f1();
}
int main()
{
auto uniq = make_unique<std::string>("Blah blah blah");
auto lambda = [uniq = move(uniq)]() {
std::cout << *uniq << std::endl;
};
// call(lambda); // doesn't compile because the lambda cannot be copied
call(std::move(lambda));
}