std::bind绑定unique_ptr

问题的来源,绑定和unique_ptr

std::bind绑定unique_ptr的时候生成的类型并非std::function,而是一个不可拷贝的类型,这跟unique_ptr的特性有关,这意味着如果需要暂时保存绑定的函数,没有能够接受对象的类型声明

如果不需要保存可以使用auto来接受绑定的对象,然后调用


void Test(int val)
{
    
}

std::unique_ptr<int> up = std::make_unique<int>();
// 错误的,无法通过编译
// std::function<void()> func = std::bind(&Test, std::move(up)); 
// 正确的,可以通过编译
auto func = std::bind(&Test, std::move(up));

其实这是绑定生成了一个不可拷贝(只可移动)的闭包类型,而std::function是可以拷贝的因此类型不匹配(就算在bind外面套一个std::move也不会有作用)

	std::_Binder<std::_Unforced,void (__cdecl*)(int),std::unique_ptr<int,std::default_delete<int>>>

其实绑定后的函数是一个内部类型

用模板

template<typename F>
class Leno
{
public:
    Leno(F& func) : task_(std::move(func)) { }
    void Run() { task_(); }
private:
    F task_;
};

用模板可以保存这种类型的闭包对象,这样就可以在需要的时候再使用了,但是有一个问题,就是这种模板,会要求Leno对象在使用时提供模板参数,这又回到了一开始的问题,这个类型是内部类型,无法提供,那么Leno对象就无法构造。

外部无感知

那就需要对外无感知,在外部想要保存这么一个闭包对象时,完全不需要提供这个闭包对象的类型,需要利用继承和模板

class LenoBase
{
public:
    virtual void Run() { }
};


template<typename F>
class Leno : public LenoBase
{
public:
    Leno(F& func) : task_(std::move(func)) { }
    void Run() override { task_(); }
private:
    F task_;
};

class LenoCallback
{
public:
    LenoCallback(std::shared_ptr<LenoBase> bs) : b_(bs) {}
    void Run() { b_->Run(); }
private:    
    std::shared_ptr<LenoBase> b_;
};

template<typename F>
LenoCallback Get(F& func)
{
    return LenoCallback(std::make_shared<Leno<F>>(func));
}

template<typename F>
std::unique_ptr<LenoCallback> GetUnique(F& func)
{
    return std::make_unique<LenoCallback>(std::make_shared<Leno<F>>(func));
}

int main() {
    std::unique_ptr<int> test = std::make_unique<int>(100);
    //auto func([pw = std::move(test)]() {
    //    cout << *pw << endl;
    //    });

    auto func = std::bind(&hahahha, std::move(test));
    function<void()> func1 = std::bind(&lalala, 10);
    std::unique_ptr<LenoCallback> callback = GetUnique(func);
    callback->Run();

    return 0;
}
  1. 基础类型LenoBase是不需要模板参数的,因此,在对外开放的类型LenoCallback中有该类型的指针,这时,LenoCallback就不需要模板参数;
  2. 需要模板参数的是Leno实现类,在函数中创建该类对象,只需要函数模板,并且利用多态实现父类指针调用子类方法;
  3. LenoBase基础类需要提供一定的虚函数实现接口;

到这里就完成了绑定unique_ptr闭包的保存,并且对外的GetGetUnique函数也不需要提供类型

posted @ 2022-09-08 18:23  leno米雷  阅读(422)  评论(0编辑  收藏  举报