Как std:: endl не использует никаких скобок, если это функция?
Вопрос в значительной степени находится в названии. Согласно С++ Reference, std::endl
- фактически функция. Рассматривая его объявление в <iostream>
, это можно проверить.
Однако, когда вы используете std::endl
, вы не используете std::endl()
. Вместо этого вы используете:
std::cout << "Foo" << std::endl;
Фактически, если вы используете std::endl()
, компилятор требует больше параметров, как указано в приведенной выше ссылке.
Кто-нибудь хотел бы объяснить это? Что особенного в std::endl
? Можем ли мы реализовать функции, не требующие каких-либо скобок при вызове?
Ответы
Ответ 1
std::endl
- объявленный шаблон функции (27.7.3.8):
template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);
Причина, по которой вы можете "передать" ее в std::cout
, состоит в том, что в шаблоне класса basic_ostream
объявлен член:
basic_ostream<charT,traits>& operator<<
( basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&) );
который определяется как возвращающий pf(*this)
(27.7.3.6.3).
std::endl
без круглых скобок относится к набору функций перегрузки - всевозможные специализации шаблона функции, но используется в контексте, где допустим указатель функции одного конкретного типа (т.е. как аргумент operator<<
), правильная специализация может быть однозначно выведена.
Ответ 2
std::endl
- это объект некоторого типа (не очень важный), который поставляется как аргумент operator<<( std::ostream &, decltype(std::endl))
.
ИЗМЕНИТЬ
Чтение другого вопроса приведет меня к мысли, что endl является шаблоном функции и что мы, скорее всего, выбираем перегрузку функции члена ostream& operator<<(ostream&(*)(ostream&))
.
Ответ 3
Хотя это функция [шаблон], стандартные потоковые манипуляторы предназначены для отправки в потоки как указатели функций (или ссылки на объектные объекты). Вставка результата вызова функции не даст вам ничего, кроме значения, которое возникает в результате вызова этой функции.
Это означает, что вы передаете сам функтор (f
), а не результат его вызова (f()
).