When I ran the following program
#include <iostream>
int main()
{
char c = 'a';
std::cout << c << std::endl;
std::cout.operator<<(c) << std::endl;
return 0;
}
I got the output
a
97
Digging further at http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt, I noticed that std::ostream::operator<<()
does not have an overload that has char
as the argument type. The function call std::cout.operator<<(a)
gets resolved to std::ostream::operator<<(int)
, which explains the output.
I am assuming that the operator<<
function between std::ostream
and char
is declared elsewhere as:
std::ostream& operator<<(std::ostream& out, char c);
Otherwise, std::cout << a
would resolve to std::ostream::operator<<(int)
.
My question is why is that declared/defined as a non-member function? Are there any known issues that prevent it from being a member function?
The set of inserters for std::basic_ostream
includes partial specializations for inserting char
, signed char
, unsigned char
and such into basic_ostream<char, ...>
streams. Note that these specializations are made available for basic_ostream<char, ...>
streams only, not for basic_ostream<wchar_t, ...>
streams or streams based on any other character type.
If you move these freestanding templates into the main basic_ostream
definition, they will become available for all specializations forms of basic_ostream
. Apparently, library authors wanted to prevent this from happening.
I don't really know why they wanted to introduce these specializations on top of the more generic
template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&,
char);
inserter, but apparently they had their reasons (optimization?).
The same situation exists for C-string inserters. In addition to the more generic inserter
template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&,
const char*);
the library specification also declares more specific
template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&,
const char*);
and so on.