#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成员函数需要可复制的类型。但是,只要您从不使用后一个功能,一切就可以了。如果编译器总是实例化所有成员函数定义并报告其中的错误(即使从未使用过),那将更加麻烦。

09-10 07:07
查看更多