Как правильно передать объект, созданный std :: bind, в функцию? - PullRequest
4 голосов
/ 29 января 2020

Давайте предположим, что я хочу передать функциональный объект, созданный std::bind по ссылке на функцию:

void myCallback(int i, int j)
{
    std::cout << "toCall , i=" << i << " j=" << j;
}

void worker(std::function<void(int)> & callback)
{
    callback(111);
}

int main(int argc, char** argv)
{
    auto foo = std::bind(myCallback, std::placeholders::_1, 222);
    worker(foo);
}

Это не компилируется

compiler error

Код серьезности Описание Ошибка состояния подавления строки файла проекта C2664 'void worker (std :: function &)': невозможно преобразовать аргумент 1 из std :: _ Binder &, int> 'в' std :: function & 'asn1test_1 D: ..... \ asn1test_1 ..... cpp 302

Однако передача по значению работает:

void worker(std::function<void(int)> callback)
{
    callback(111);
}

Когда Я избегаю "auto" и использую вместо этого

std::function<void(int)> foo = std::bind(myCallback, std::placeholders::_1, 222);

, он работает как с передачей по ссылке, так и по значению.

Q1: Почему это поведение?

Q2: Какой будет «правильный» способ или тип данных для передачи объекта, созданного std::bind, в функцию?

Ответы [ 4 ]

4 голосов
/ 29 января 2020

std::bind не возвращает std::function, по крайней мере, это не требуется. Когда вы делаете

auto foo = std::bind(myCallback, std::placeholders::_1, 222);
worker(foo);

foo не является std::function, а worker требуется неконстантная ссылка на std::function, поэтому компилятор выдает ошибку. Если вы переключите worker на

void worker(const std::function<void(int)> & callback)

, то у вас будет константная ссылка, и она может быть связана с временным объектом, который будет производить преобразование foo в std::function.


Я также хотел бы отметить, что, поскольку у нас есть лямбды, особенно общие c, std::bind действительно не нужны. Сохраняя изменения для работника, вы могли бы вместо этого сделать foo

auto foo = [](auto var){ return myCallback(var, 222); };
4 голосов
/ 29 января 2020

std::bind() не возвращает std::function, но тип, определенный реализацией, который конвертируется в std::function.

Когда worker() принимает его callback параметр как неконстантная ссылка, которая не позволяет компилятору выполнять какие-либо неявные преобразования, поскольку неконстантная ссылка не может быть привязана к временному объекту. Ссылка потребует, чтобы фактический объект std::function был заранее создан явно, например:

std::function<void(int)> foo = std::bind(myCallback, std::placeholders::_1, 222);
worker(foo);

Изменение worker() для получения параметра callback по значению или по ссылке const позволяет компилятору выполнить неявное преобразование для вас, чтобы вы могли передать результат std::bind() как есть, и компилятор создаст для вас временную переменную std::function.

2 голосов
/ 29 января 2020

Если вы хотите избежать затрат на преобразование в std :: function, вы можете использовать шаблон:

template<class CB> void worker(CB callback) {
    callback(111);
}
1 голос
/ 29 января 2020

Это должно быть:

void worker(std::function<void(int)> const& callback) {
    callback(111);
}

, потому что тогда можно сделать неявное преобразование из foo во временный std::function объект.

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