C++ 如果std::函数捕获了唯一的\u ptr,那么如何复制它? #包括 #包括 #包括 结构PacketFrom { typedef std::unique_ptr SPtr; }; 模板 R类{ 公众: 无效队列读取(P*t) { doSomething([t=typename PacketFrom::SPtr(t)]({test(std::move(t));}); } 无效剂量测量(标准::函数f){ } 无效测试(包装发件人::SPtr p){ } }; int main() { R; 返回0; }
如果lambda函数是通过copy传递的,那么该代码如何工作?lambda拥有一个不可复制的C++ 如果std::函数捕获了唯一的\u ptr,那么如何复制它? #包括 #包括 #包括 结构PacketFrom { typedef std::unique_ptr SPtr; }; 模板 R类{ 公众: 无效队列读取(P*t) { doSomething([t=typename PacketFrom::SPtr(t)]({test(std::move(t));}); } 无效剂量测量(标准::函数f){ } 无效测试(包装发件人::SPtr p){ } }; int main() { R; 返回0; },c++,C++,如果lambda函数是通过copy传递的,那么该代码如何工作?lambda拥有一个不可复制的唯一\u ptr。我认为它只是没有捕获唯一的ptr,所以我添加了test(),以确保它正在捕获。但是,代码编译得很好。从这个意义上说,这段代码实际上不“工作”。它可以编译,但这只是因为您从未调用queue\u read 如果您尝试使用它(这迫使编译器实际实例化R::queue\u read,直到那时它才需要执行此操作),那么每个编译器都会出现一个错误: #include <iostream>
唯一\u ptr
。我认为它只是没有捕获唯一的ptr,所以我添加了test()
,以确保它正在捕获。但是,代码编译得很好。从这个意义上说,这段代码实际上不“工作”。它可以编译,但这只是因为您从未调用queue\u read
如果您尝试使用它(这迫使编译器实际实例化R::queue\u read
,直到那时它才需要执行此操作),那么每个编译器都会出现一个错误:
#include <iostream>
#include <memory>
#include <functional>
struct PacketFrom
{
typedef std::unique_ptr<PacketFrom> SPtr;
};
template<class P>
class R{
public:
void queue_read(P *t)
{
doSomething([t = typename PacketFrom::SPtr(t)](){test(std::move(t));});
}
void doSomething(std::function<void()> f) {
}
void test(PacketFrom::SPtr p) {
}
};
int main()
{
R<PacketFrom> r;
return 0;
}
模板
R类{
公众:
无效队列读取(P*t)
{
剂量测定法([this,t=std::unique_ptr(t)](){test(std::move(t));});
}
无效剂量测量(标准::函数f){
(f)无效;
}
无效试验(标准:唯一性试验
P){
(无效)p;
}
};
int main()
{
R;
r、 队列读取(新整数(1));
返回0;
}
clang 9.0:
错误:调用“std::unique\u ptr”的已删除构造函数
剂量测定法([this,t=std::unique_ptr(t)](){test(std::move(t));});
gcc 9.2:
错误:使用已删除函数“std::unique\u ptr::unique\u ptr(const std::unique\u ptr&)[带_Tp=int;_Dp=std::default\u delete]”
11 |剂量测定法([this,t=std::unique_ptr(t)]({test(std::move(t));});
MSVC 19.22:
错误C2280:'std::unique_ptr::unique_ptr(const std::unique_ptr&'):尝试引用已删除的函数
(谢谢Richard!)
同样,这里的关键是编译器实际上没有编译queue\u read
的代码,因为没有必要。由于在类主体中定义,函数是隐式内联的
。为某些P
实例化R
只会实例化声明,而不会实例化其成员函数的定义。只有当您真正调用queue\u read
时,编译器才会抱怨
顺便说一句,这是件好事。您可以使用std::vector
并执行所有不需要复制的操作,即使某些std::vector
成员函数需要可复制类型。但只要不使用后面的函数,一切都很好。如果编译器总是实例化所有的成员函数定义并报告其中的错误(即使从未使用过),这将是非常麻烦的
如果std::函数捕获了唯一的\u ptr,那么如何复制它
std::function
不会捕获任何内容
捕获不可复制对象(如std::unique_ptr
)的lambda本身是不可复制的。这样的lambda不满足,任何其他不可复制的函数对象类型也不满足要求函子可复制的std::function
的要求。标准规则(来自最新草案):
[func.wrap.func.con]
error C2280: 'std::unique_ptr<P,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
模板函数(F);
要求:F应可施工
然而,代码编译得很好
当格式错误的函数是模板的未使用函数时,这是典型的。如果您试图调用该函数,它将无法编译。此处未复制任何内容
f
是根据queue\u read
中的lambda表达式构造的。但它仍然不应该起作用,因为在doSomething
中,您不再知道f
无法复制;G++和MSVC编译:建议[语言律师] TAG始终记住C++有这种独特的失败模式,在这里询问编译器“这是一个有效程序”有错误的正误…<代码>(t)](({测试(STD::移动(t));});<代码>有这么多()()({][][}}[[]]{]])是正常的吗((C++中没有空格)你知道为什么相同的代码在这里工作吗?我已经从这里写过我的问题,但是它不起作用。works@GuerlandoOCs如果你给我链接到类TunIO
的实例化,我可以看一下,但是我没有时间去挖掘一些实例化和cla的定义我自己在那里用作TunIO
的模板参数。@GuerlandoOCsasync\u read\u some
不接受std::function
而是HANDLER&
,其中HANDLER
是一个模板类型。换句话说,这里没有什么可看的:lambda被移动到函数中。@GuerlandoOCs没有相同的代码t这里。我既看不到std::unique\u ptr
也看不到std::function
@GuerlandoOCs No。每个lambda都有一个唯一的、不可命名的类型。这就是模板参数将具有的类型。可以将其视为struct\u SOME\u HASH\uuu{auto operator()(/*您的参数*/){/*您的代码*/};/*您的捕获*/}
-在较高的层次上。如果std::function
不存在,lambda将像现在一样工作(但接受将lambda捕获到非模板方法中基本上需要std::function
重新实现)。lambda不是std::function
,不会自动“衰减”到它们(但可以无缝转换为它们)。
error: call to deleted constructor of 'std::unique_ptr<int>'
doSomething([this, t = std::unique_ptr<P>(t)]() { test(std::move(t)); });
error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'
11 | doSomething([this, t = std::unique_ptr<P>(t)]() { test(std::move(t)); });
error C2280: 'std::unique_ptr<P,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
template<class F> function(F f);