std :: bind с подвижным параметром - PullRequest
0 голосов
/ 30 марта 2020

У меня проблемы с std::bind и я использую подвижный тип в качестве параметра. Читается this и this , но в этих случаях я действительно вижу проблему, так как там, где OP хочет иметь ссылку rvalue внутри привязки. То, что я хочу, это иметь lvalue, но просто перемещать-конструировать его при вызове 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 был перемещаемым конструктивно - как показано в комментариях, добавление копии ctor решает все (и если все остальное не удается, я просто go, что путь). Единственное, что, с моей точки зрения, могло бы запретить это, если результат std::bind должен быть копируемым, но cppreference сообщает:

Тип возврата std: : bind - это CopyConstructible, если все его объекты-члены (указанные выше) являются CopyConstructible, и иначе - MoveConstructible.

Я думал, что если тип, как переменная хранится в привязке, выводится из вызова тогда std::move может вызвать попытку сохранить ссылку на rvalue, таким образом, второй вызов, в котором я явно указываю параметры шаблона (и ожидаю, что само связывание будет иметь член типа Param, который может быть перемещаемым и назначаемым).

Что мне здесь не хватает?

1 Ответ

1 голос
/ 30 марта 2020

Ваши проблемы происходят от std::function.

std::bind возвращает некоторый вызываемый объект с Param в качестве переменной-члена. Когда создается экземпляр std::function, все члены этого функтора, сгенерированные bind, сохраняются путем копирования . Когда конструктор копирования Param закомментирован, просто невозможно создать оболочку std::function. И это ваша проблема.

В качестве решения избавьтесь от std::function и просто передайте любой вызываемый объект в качестве параметра шаблона:

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

Live demo

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...