Как потоковые манипуляторы в 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;

Источник

Другие вопросы по тегам