Most IO stream manipulators are regular functions with the following signature:
std::ios_base& func( std::ios_base& str );
However
You need to put << before the endl. It is a member of ofstream:
namespace std {
template <class charT, class traits = char_traits<charT> >
class basic_ostream {
public:
basic_ostream<charT,traits>& operator<<(
basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
// ...
};
}
endl works like a "/n" to skip the line, so you need a cout line to skip
Given a statement expression of the form
std::cout << std::endl;
The compiler has information about the type of std::cout
- which is a specialisation of the templated std::basic_ostream
which looks something like (omitting the containing namespace std
).
template <class charT, class traits = char_traits<charT> >
class basic_ostream
{
public:
basic_ostream<charT,traits>& operator<<(
basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
};
Since the compiler has information about the type of std::cout
it knows what charT
and traits
are to specialise the preceeding template.
The above causes std::endl
in the expression std::cout << std::endl
to match to the specific std::basic_ostream<charT, traits>& endl( std::basic_ostream<charT, traits>&)
.
The reason type deduction doesn't work in
auto myendl = std::endl;
is because std::endl
is a templated function, and this declaration provides no information to specialise that template (i.e. picking what charT
or traits
are). If it can't specialise the templated std::endl
, it can't infer that function's return type, so the type deduction fails.
The operator<<
in question is a member of std::basic_ostream
:
namespace std {
template <class charT, class traits = char_traits<charT> >
class basic_ostream {
public:
basic_ostream<charT,traits>& operator<<(
basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
// ...
};
}
Since the call is to std::cout << std::endl
, or equivalently std::cout.operator<<(std::endl)
, we already know the exact instantiation of basic_ostream
: std::basic_ostream<char, std::char_traits<char>>
, aka std::ostream
. So the member function of cout
looks like
std::ostream& operator<<(std::basic_ostream<char, std::char_traits<char>>& (*pf)
(std::basic_ostream<char, std::char_traits<char>>&));
This member function is not a function template, just an ordinary member function. So the question remaining, is can it be called with the name std::endl
as an argument? Yes, initializing the function argument is equivalent to a variable initialization, as though we had written
std::basic_ostream<char, std::char_traits<char>>& (*pf)
(std::basic_ostream<char, std::char_traits<char>>&) = std::endl;
Because basic_ostream
has a templated overload of operator<<
that expects just such a function pointer:
basic_ostream<charT, traits>& operator<<(basic_ios<charT, traits>& (*pf)(basic_ios<charT, traits>&));