Как потоковые манипуляторы в C++ могут быть функциями?
При вызове функции в C++ пишется имя функции с последующим ()
чтобы отличить его как вызов функции. Почему я не могу вызывать функции потокового манипулятора таким же образом?
Почему это не разрешено?
cout << "Hello!" << endl();
не endl
переменный холдинг \n
?
Спасибо!
3 ответа
Разве endl не является переменной, содержащей \ n?
Нет. std::endl
это функция, определенная в глобальном пространстве имен
template<typename _CharT, typename _Traits>
inline basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os)
{ return flush(__os.put(__os.widen('\n'))); }
В выражении std::cout << endl_or_something
правая сторона <<
является аргументом вызова operator<<
(первый аргумент std::ostream
неявно). Таким образом, endl_or_something должен иметь тип int, double или другой тип, который может быть преобразован в один из возможных аргументов operator<<
, Существует перегруженная версия этого оператора, которая берет указатели на функции (функции, которые ссылаются на std::ostream
и вернуть ссылку на std::ostream
):
// [27.6.2.5] formatted output
// [27.6.2.5.3] basic_ostream::operator<<
//@{
/**
* @brief Interface for manipulators.
*
* Manipulators such as @c std::endl and @c std::hex use these
* functions in constructs like "std::cout << std::endl". For more
* information, see the iomanip header.
*/
__ostream_type&
operator<<(__ostream_type& (*__pf)(__ostream_type&))
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 60. What is a formatted input function?
// The inserters for manipulators are *not* formatted output functions.
return __pf(*this);
}
поскольку std::endl
совпадения подписи, это может быть использовано в выражении
std::cout << "Hello!" << std::endl;
или эквивалентно
std::cout << "Hello!";
std::endl( std::cout);
Однако обратите внимание, что этот манипулятор часто ошибочно используется, когда требуется простой перевод строки, что приводит к снижению производительности буферизации. В таких случаях используйте просто "\n"
,
Почему это не разрешено?
cout << "Hello!" << endl();
std::endl принимает один аргумент, std::ostream. Вы можете видеть, что это может быть вызвано с:
return __pf(*this);
средства
return std::endl( *this); // std::endl( std::cout);
Нет версии std::endl
это не принимает никаких параметров, поэтому он может быть вызван с
std::endl()
В выражении
std::cout << std::endl;
это обозначает аргумент operator<<
, он передается как указатель на функцию, а затем вызывается в теле operator<<
,
Потоковые манипуляторы - это функции. Как таковые, они могут быть вызваны с помощью оператора вызова ()
, Вот как бы вы назвали std::endl
в потоке:
std::endl(std::cout);
Это способ вызова его для каждого потока, который вы хотите использовать. std::endl
, Это потому что std::endl
это функция, которая возвращает ссылку на объект потока Это очень странный способ сделать это, поэтому есть удобная функция для потоковой передачи синтаксиса:
std::ostream& operator<<(std::ostream& (*manip)(std::ostream&));
Это перегрузка operator<<()
который берет поток с левой стороны и манипулятор с правой стороны. std::endl
технически это функция, поэтому она может быть преобразована в указатель на функцию.
Внутри реализации этой перегрузки, manip
называется в значительной степени, как я только что показал вам. Это позволяет синтаксис, такой как:
std::cout << "Hello, World" << std::endl;
Если вы пошли и позвонили std::endl
используя оператор вызова, он вернет ссылку на поток. Существует еще одна перегрузка operator<<()
это занимает const void*
в качестве аргумента. Это будет перегрузка, которая непреднамеренно вызывается.
std::cout << std::endl(std::cout); // prints a newline then an address
Манипуляторы - это функции, специально предназначенные для использования в сочетании с операторами вставки (<<) и извлечения (>>) в объектах потока, например:
cout << boolalpha;
Они по-прежнему являются обычными функциями и могут также вызываться как любая другая функция, использующая объект потока в качестве аргумента, например:
boolalpha (cout);
Итак, в вашем коде вы можете сделать
cout << "Hello!";
endl(cout);
вместо
cout << "Hello!" << endl;