С++ 11 std:: function и безупречная переадресация

Почему определение std:: function < > :: operator() в стандарте С++:

R operator()(ArgTypes...) const;

а не

R operator()(ArgTypes&&...) const;

?

Можно подумать, что для правильной пересылки параметров нам нужен && а затем использовать std::forward<ArgTypes>... в теле функции при переадресации вызова?

Я частично переопределял std:: function, чтобы проверить это, и я узнал, что если я использую & &, я получаю "не могу связывать" xxx 'lvalue с "xxx & &" из g++, когда я пытаюсь позже передать параметры по значению оператору(). Я думал, что я достаточно разбираюсь в концепциях rvalue/forwarding, но все же я не могу понять это. Что мне не хватает?

Ответ 1

Идеальная переадресация работает только тогда, когда сама функция (в данном случае operator()) построена шаблоном и выводятся аргументы шаблона. Для std::function вы получаете типы аргументов operator() из параметров шаблона самого класса, что означает, что они никогда не будут выводиться из любых аргументов.

Весь трюк за совершенной переадресацией - это часть вычитания аргумента шаблона, которая вместе со свертыванием ссылки является идеальной пересылкой.

Я просто позвоню на мой другой ответ о std::forward здесь, где я объясню, как работает совершенная переадресация (и std::forward).

Обратите внимание, что std::function operator() не нуждается в идеальной переадресации, так как сам пользователь решает, какие параметры должны быть. Это также является причиной, по которой вы не можете просто добавить && в operator(); возьмите этот пример:

void foo(int){}

int main(){
  // assume 'std::function' uses 'ArgTypes&&...' in 'operator()'
  std::function<void(int)> f(foo);
  // 'f 'operator()' will be instantiated as
  // 'void operator()(int&&)'
  // which will only accept rvalues
  int i = 5;
  f(i); // error
  f(5); // OK, '5' is an rvalue
}