#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;
}
如果通过复制传递lambda函数,此代码如何工作? Lambda拥有一个
unique_ptr
,无法复制。我以为这根本不是在捕获unique_ptr,所以我添加了test()
只是为了确保它正在捕获。但是代码可以很好地编译。 最佳答案
从这个意义上讲,这段代码实际上并不“起作用”。它可以编译,但这仅是因为您从未调用queue_read
。
如果您尝试使用它(这会迫使编译器实际实例化R<P>::queue_read
,直到此时才必须这样做),那么每个编译器都会出错:
template<class P>
class R{
public:
void queue_read(P *t)
{
doSomething([this, t = std::unique_ptr<P>(t)]() { test(std::move(t)); });
}
void doSomething(std::function<void()> f) {
(void)f;
}
void test(std::unique_ptr<P> p) {
(void)p;
}
};
int main()
{
R<int> r;
r.queue_read(new int(1));
return 0;
}
铛9.0:
gcc 9.2:
MSVC 19.22:
https://godbolt.org/z/KmjVJB(感谢Richard!)
同样,这里的关键是编译器实际上没有编译
queue_read
的代码,因为没有必要。由于在类主体中定义,该函数隐式为inline
。实例化某些R<P>
的P
只会导致声明,而不会实例化其成员函数的定义。仅当您实际调用queue_read
时,编译器才需要提示。顺便说一句,这是一件好事。您可以使用
std::vector<MoveOnlyType>
并执行不需要复制的所有操作,即使某些std::vector
成员函数需要可复制的类型。但是,只要您从不使用后一个功能,一切就可以了。如果编译器总是实例化所有成员函数定义并报告其中的错误(即使从未使用过),那将更加麻烦。