注意:这是这个类似问题的变体,但具有可移动对象和显式声明的析构函数。
下面的代码
#include <functional>
#include <memory>
struct S
{
~S();
std::unique_ptr<int> x;
};
std::function<void(S)> x = [](S){};
Run Code Online (Sandbox Code Playgroud)
编译失败:
<source>:11:28: error: conversion from '<lambda(S)>' to non-scalar type 'std::function<void(S)>' requested
11 | std::function<void(S)> x = [](S){};
|
Run Code Online (Sandbox Code Playgroud)
如果我执行以下任一操作,它会按预期编译:
x成员变量;const S&而不是S.为什么会这样?为什么明确声明很~S重要?
S不可复制,因为std::unique_ptr不可复制。
S也是不可移动的,因为析构函数的用户声明会阻止隐式声明移动操作。您必须手动声明(和默认/定义)它们。
一般来说,应该遵循五法则:如果声明析构函数,那么您还应该声明并默认/删除/定义所有复制/移动构造函数/赋值运算符。但是,只要功能上可能,请避免声明其中任何一个(零规则)。
然后std::function<void(S)>不能与 lambda 一起使用,因为它operator()需要std::function<void(S)>一个S作为参数,并且在转发到它时需要S从它自己的 lambda 参数进行移动构造S。std::function<void(S)>因此,禁止从 lambda构造。
在 lambda 中使用const S&代替是S有效的,因为这样就没有必须移动构造的参数对象,并且使用右S值 from调用 lambdastd::function<void(S)>::operator()将是有效的。