Most IO stream manipulators are regular functions with the following signature:
std::ios_base& func( std::ios_base& str );
However some manipulators (including the most frequently used ones - std::endl
and std::flush
) are templates of the following form:
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& func(std::basic_ostream<CharT, Traits>& os);
Then, how does the compilation of std::cout << std::endl;
succeed given that the following example fails:
$ cat main.cpp
#include <iostream>
int main()
{
auto myendl = std::endl;
std::cout << myendl;
}
$ g++ -std=c++11 main.cpp -o main
main.cpp: In function ‘int main()’:
main.cpp:5:24: error: unable to deduce ‘auto’ from ‘std::endl’
auto myendl = std::endl;
^
It is clear that the context (in std::cout << std::endl;
) helps the compiler to disambiguate the reference to std::endl
. But what are the rules that govern that procedure? It looks like a real challenge for overloading resolution, which has to answer two questions at once:
- Which specialization of
std::endl<CharT, Traits>()
doesstd::endl
refer to? - Which function does the
operator<<
refer to?
Template argument deduction (1) should happen before overload resolution (2), but it seems that (at least some part of) (2) is required to be performed in order for (1) to succeed.
Somewhat related but no-way duplicate questions are:
- Does std::endl work with both cout and wcout?
- Why does endl(std::cout) compile
- How does std::flush work?
None of those questions and neither answers to them address the workings of template argument deduction that should precede overload resolution but must be helped by the latter.
Follow-up question: How does overload resolution work when an argument is an overloaded function?
You need to put << before the endl. It is a member of ofstream:
endl works like a "/n" to skip the line, so you need a cout line to skip
The
operator<<
in question is a member ofstd::basic_ostream
:Since the call is to
std::cout << std::endl
, or equivalentlystd::cout.operator<<(std::endl)
, we already know the exact instantiation ofbasic_ostream
:std::basic_ostream<char, std::char_traits<char>>
, akastd::ostream
. So the member function ofcout
looks likeThis 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 writtenBecause
basic_ostream
has a templated overload ofoperator<<
that expects just such a function pointer:Given a statement expression of the form
The compiler has information about the type of
std::cout
- which is a specialisation of the templatedstd::basic_ostream
which looks something like (omitting the containingnamespace std
).Since the compiler has information about the type of
std::cout
it knows whatcharT
andtraits
are to specialise the preceeding template.The above causes
std::endl
in the expressionstd::cout << std::endl
to match to the specificstd::basic_ostream<charT, traits>& endl( std::basic_ostream<charT, traits>&)
.The reason type deduction doesn't work in
is because
std::endl
is a templated function, and this declaration provides no information to specialise that template (i.e. picking whatcharT
ortraits
are). If it can't specialise the templatedstd::endl
, it can't infer that function's return type, so the type deduction fails.