lundi 30 mars 2020

std::bind with a movable paramter

I am having trouble with std::bind and using a moveable type as a parameter. Is read this and this, but in those cases I actually see the issue since there the OP want's to have a rvalue reference inside the bind. What I want to is have a lvalue, but just to move-construct it when calling std::bind. Here is a minimal sample:

#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;
}

So I want Param to be move constructible - as shown in the comments adding a copy ctor solves everything (and if everything else fails I will just go that way). The only thing that from my point of view could prohibit this is if the result of std::bind must be copy constructible, but cppreference states:

The return type of std::bind is CopyConstructible if all of its member objects (specified above) are CopyConstructible, and is MoveConstructible otherwise.

I thought that if the type how the variable is stored in the bind is deduced from the call then std::move could cause an attempt to store a rvalue reference, thus the second call where I explicitly state the template parameters (and would expect the bind itself to have a member of type Param which is move constructible and move assignable).

What am I missing here?

Aucun commentaire:

Enregistrer un commentaire