Ответ 1
Функция (указатель) может быть привязана к универсальной ссылке. Пример:
void f(int) {}
template <typename T>
void foo(T&&) {}
foo(f); // OK
Однако перегруженная функция не может. То есть, если вы добавите вторую перегрузку f
, скажем,
void f(double) {}
вызов foo(f)
завершится с ошибкой.
Поставьте себя на обувь компилятора. Он должен пройти f
до foo
, и есть две функции с именем f
, каждая из которых имеет другой тип. Если мы сообщим тип, то компилятор может однозначно выбрать правильный f
. Например,
foo(static_cast<void (*)(int)>(f));
компилируется и передает void f(int)
(после преобразования функции в указатель) в foo
.
Однако мы не сообщаем тип. Мы скорее просим компилятор вывести его.
Аналогично f
, тот же аргумент применяется к std::endl
, потому что это шаблон функции, и поэтому имя std::endl
представляет собой набор функций с одинаковым именем, но с разными типами.
Теперь вы можете видеть, что причиной ошибки является тот факт, что мы предоставляем набор перегрузки и запрашиваем вывод типа. Следовательно, это не относится к универсальным ссылкам.
std::cout << std::endl
работает, потому что basic_ostream::operator <<
не является шаблоном и не пытается вывести тип переданного аргумента. Это функция, которая принимает один конкретный тип std::endl
.