Search code examples
c++manipulators

How can stream manipulators in C++ be functions?


When calling a function in C++, function's name is written followed by () to distinguish it as a function call. Why can't I call stream manipulator functions in the same way?

Why this isn't allowed?:

cout << "Hello!" << endl();

Isn't endl a variable holding \n?

Thanks!


Solution

  • Isn't endl a variable holding \n?

    No, it is not. std::endl is a function defined in global namespace

      template<typename _CharT, typename _Traits>
        inline basic_ostream<_CharT, _Traits>& 
        endl(basic_ostream<_CharT, _Traits>& __os)
        { return flush(__os.put(__os.widen('\n'))); }
    

    In expression std::cout << endl_or_something right hand side of << is an argument of a call to operator<< (first argument is std::ostream implicitly). So endl_or_something should be an int, double or other type that can be converted to one of the possible arguments of operator<<. There is an overloaded version of this operator that takes pointers to functions ( functions which take reference to std::ostream and return reference to 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);
      }
    

    Since std::endl signature matches, it can be used in expression

    std::cout << "Hello!" << std::endl;
    

    or equivalently

    std::cout << "Hello!";
    std::endl( std::cout);
    

    Note however that this manipulator is often mistakenly used when a simple newline is desired, leading to poor buffering performance. In such cases use just "\n".


    Why this isn't allowed?:

    cout << "Hello!" << endl();
    

    std::endl takes one argument, std::ostream. You can see that it can be called with:

    return __pf(*this);
    

    means

    return std::endl( *this); // std::endl( std::cout);
    

    There is no version of std::endl that takes no parameters so it could be called with

    std::endl()
    

    In expression

    std::cout << std::endl;
    

    it denotes an argument to operator<<, it is passed as a pointer to function and then called in body of operator<<.