Why does an ostream iomanip not need template parameters when passed to operator<<?

Viewed 59

In namespace std, of the gnu stdc++ header ostream, this is the definition of std::endl:

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

Why is it possible to write std::cout << std::endl; where endl is used without template parameters?

1 Answers

std::basic_ostream<CharT,Traits>::operator<< taking manipulators as function pointer. Template argument deduction is performed when being passed template like std::endl, thus template arguments don't need to be specified explicitly.

When possible, the compiler will deduce the missing template arguments from the function arguments. This occurs when a function call is attempted and when an address of a function template is taken.

This mechanism makes it possible to use template operators, since there is no syntax to specify template arguments for an operator other than by re-writing it as a function call expression.

#include <iostream>
int main() 
{
    std::cout << "Hello, world" << std::endl;
    // operator<< is looked up via ADL as std::operator<<,
    // then deduced to operator<<<char, std::char_traits<char>> both times
    // std::endl is deduced to &std::endl<char, std::char_traits<char>>
}

Given std::cout << std::endl;, the parameter type of the appropriate operator<< is std::basic_ostream<char,std::char_traits<char>>& (*func)(std::basic_ostream<char,std::char_traits<char>>&), then the template arguments of std::endl would be deduced as char and std::char_traits<char>.

Related