How can stream manipulators in C++ be functions? [duplicate]
-
21-12-2019 - |
Question
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<<
.
OTHER TIPS
Manipulators are functions specifically designed to be used in conjunction with the insertion (<<) and extraction (>>) operators on stream objects, for example:
cout << boolalpha;
They are still regular functions and can also be called as any other function using a stream object as argument, for example:
boolalpha (cout);
So, in your code, you can do
cout << "Hello!";
endl(cout);
instead of
cout << "Hello!" << endl;
Stream manipulators are functions. As such, they can be called using the call operator ()
. Here's how you would call std::endl
on a stream:
std::endl(std::cout);
This is the way it would have to be called for each and every stream on which you want to use std::endl
. This is because std::endl
is a function that takes a returns a reference to a stream object. This is a very quirky way of doing it, so there is a convenience function to stream line the syntax:
std::ostream& operator<<(std::ostream& (*manip)(std::ostream&));
This is an overload of operator<<()
that takes a stream on its left hand side and a manipulator on its right hand side. std::endl
is technically a function, so it can be converted to a function pointer.
Inside the implementation of this overload, manip
is called pretty much how I just showed you. This allows syntax such as:
std::cout << "Hello, World" << std::endl;
If you went ahead and called std::endl
using the call operator it will return a reference to the stream. There is another overload of operator<<()
that takes a const void*
as its argument. That will be the overload that is inadvertently called.
std::cout << std::endl(std::cout); // prints a newline then an address