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?
These operators cannot be overloaded because if we overload them it will make serious programming issues. For an example the sizeof operator returns the size of the object or datatype as an operand. This is evaluated by the compiler.
You can not do it as a member function, because the implicit this parameter is the left hand side of the << -operator. (Hence, you would need to add it as a member function to the ostream -class.
In C++, stream insertion operator “<<” is used for output and extraction operator “>>” is used for input.
The std::ostream , the std::istream or the std::iostream are base classes of stream types (e.g. std::stringstream , std::fstream , etc.) in the Standard Library. These classes are protected against instantiation, you can instantiate their derived classes only.
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.
One reason is following the general C++ advice of preferring non-member non-friend functions to member functions. This is item 23 in Scott Meyer's Effective C++. This is discussed in stackoverflow.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With