Проблема в том, что с помощью std :: bind связать функцию - PullRequest
0 голосов
/ 25 апреля 2020

Я не могу скомпилировать следующий код c ++, ошибка отображается внутри функции call2, я полагаю, call и call2 одинаковы, но ошибка возникает на call2. Я вставляю информацию об ошибке в соответствующую строку кода. Кто-нибудь может мне помочь и объяснить, что именно является подписью f после выполнения std :: bind? Также я предоставляю call3, который использует beast :: bind_front_handler для связывания функции, и она компилируется без ошибок.

Кстати: мой компилятор clang со стандартом c ++ 14. Спасибо за ваше время.

#include <boost/beast.hpp>
#include <iostream>
#include <string>

namespace beast = boost::beast;

void subfunc(int a) { std::cout << "a=" << a << std::endl; }

void func(int n, std::string s, std::function<void(int)> &&subf) { subf(n); }

template <typename F>
void call(F &&f2) {
  auto f = std::bind(func, 1, "100", std::forward<F>(f2));
  f();
}

void call2(std::function<void(int)> &&f2) {
  auto f = std::bind(func, 1, "100", std::move(f2));
  f(); // No matching function for call to object of type 'std::__1::__bind<void (&)(int, std::__1::basic_string<char>, std::__1::function<void (int)> &&), int, char const (&)[4], std::__1::function<void (int)> >'
}

void call3(std::function<void(int)> &&f2) {
  auto f = beast::bind_front_handler(func, 1, "100", std::move(f2));
  f();
}

int main() {
  call(subfunc);
  call2(subfunc);
  call3(subfunc);
  return 0;
}

1 Ответ

1 голос
/ 25 апреля 2020

Lvalue не может быть привязано к rvalue reference .

Если у вас есть:

void bar(int&&) {}
int i = 0;
bar(i);                // error

, последняя строка не будет компилироваться.

Это причина, по которой ваш код завершается ошибкой во втором случае.


std::bind принимает все переданные аргументы и копирует / перемещает их в элемент данных вновь сгенерированного функтора:

std::bind(func,arg1,arg2)

дает вам:

class closure1 {
    Arg1 arg1;
    Arg2 arg2;

    void operator()() {
         func(arg1,arg2);
    }
};

и предоставляет также оператор вызова функции, в котором arg(s) передается по значению как Lvalues ​​ (4-я точка в Функция-член operator () секция std::bind ссылка :

В противном случае обычный хранимый аргумент arg передается вызываемому объекту как аргумент lvalue: аргумент vn в Вызов std :: invoke выше - просто arg, а соответствующий тип Vn - это T cv &, где cv - та же квалификация cv, что и для g.

Так вот:

auto f = std::bind(func, 1, "100", std::forward<F>(f2));

генерирует

class closure2 {
       int i = 1;
       std::string s = "100";
       std::forward<void(int)> f;
       void operator()() {
             func(i,s,f);    // [1]
       }
};

и в [1] проблема, потому что f как lvalue не может быть привязан от d до rvalue reference объявлено в:

void func(int n, std::string s, std::function<void(int)> &&subf)

вы можете добавить еще одну перегрузку, принимая lvalue reference :

void func2(int n, std::string s, std::function<void(int)> &subf)

и позвонить bind с этой версией ваших перегрузок.


Нет проблем с bind_front_handler, потому что в этой реализации все члены данных сгенерированного функтора перенаправляются к цели:

 func(...,std::forward< std::function<void()> >(f));

поэтому f будет преобразован в rvalue reference , и func может принять этот аргумент.


Demo

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