Most IO stream manipulators are regular functions with the following signature:
std::ios_base& func( std::ios_base& str );
However
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 basic_ostream
{
public:
basic_ostream& operator<<(
basic_ostream& (*pf)(basic_ostream&));
};
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.
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.