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