【问题标题】:std::bind with a movable paramter带有可移动参数的 std::bind
【发布时间】:2020-03-30 09:46:32
【问题描述】:

我在使用std::bind 并使用可移动类型作为参数时遇到问题。读取thisthis,但在这些情况下,我实际上看到了问题,因为OP 希望在绑定中有一个右值引用。我想要的是有一个左值,但只是在调用std::bind 时移动构造它。这是一个最小的示例:

#include <functional>

struct Foo
{
    using Callback = std::function<void(int)>;

    void Do(const Callback &callback)
    {
        callback(5);
    }
};

class Param
{
private:
    Param() {};

public:
    Param(Param&&)
    {
    }

    // commenting out copy ctor triggers the last two invocations in Bar() to fail
#if 1   
    Param(const Param&)
    {
    }
#endif

    Param& operator=(Param&&)
    {
        return *this;
    }

    static Param Create()
    {
        return Param();
    }

    int value_ = 10;
};

struct Bar
{
    Bar()
    {
        Foo f;
        f.Do(std::bind(&Bar::Callback1, this, std::placeholders::_1));
        Param p(Param::Create());
        f.Do(std::bind(&Bar::Callback2, this, std::move(p), std::placeholders::_1)); // does not work w/o copy ctor
        f.Do(std::bind<decltype(&Bar::Callback2), Bar*, Param>(&Bar::Callback2, this, std::move(p), std::placeholders::_1)); // does not work w/o copy ctor
    }

    void Callback1(int a)
    {
        printf("%d\n", a);
    }

    void Callback2(const Param &p, int a)
    {
        printf("%d %d\n", a, p.value_);
    }
};

int main()
{
    Bar b;
}

所以我希望 Param 可以移动构造 - 如 cmets 所示,添加一个复制 ctor 可以解决所有问题(如果其他所有问题都失败了,我会这样做)。在我看来,唯一可以禁止的是 std::bind 的结果必须是可复制构造的,但 cppreference 声明:

如果 std::bind 的所有成员对象(上面指定)都是 CopyConstructible,则返回类型是 CopyConstructible,否则是 MoveConstructible。

我认为如果从调用中推断出变量在绑定中的存储类型,那么std::move 可能会导致尝试存储右值引用,因此我在第二次调用中明确声明了模板参数(并且会期望绑定本身具有 Param 类型的成员,该成员可移动构造和移动分配)。

我在这里错过了什么?

【问题讨论】:

    标签: c++11


    【解决方案1】:

    你的烦恼来自std::function

    std::bind 返回一些以Param 作为成员变量的可调用对象。当std::function 实例被创建时,bind 生成的函子的所有成员都通过复制 存储。当Param 的复制构造函数被注释掉时,就不可能创建std::function 包装器。这是你的问题。

    作为解决方案,摆脱std::function,只需将任何可调用对象作为模板参数传递:

    template<class F>
    void Do(F&& callback)
    {
        callback(5);
    }
    

    Live demo

    【讨论】:

    • 感谢您的回答,遗憾的是,我不能使用这种方法,因为我实际上有一个接受 std::function 回调的类,我只是想用额外的参数绑定我的成员函数作为那个回调。我只是将其调整为可复制,但这看起来仍然很奇怪。是否有机会改进 std::function 以允许这样做?
    猜你喜欢
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 2019-04-30
    相关资源
    最近更新 更多