Why is operator<< function between std::ostream and char a non-member function?

R Sahu

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?

AnT

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.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream<char>’ and ‘<unresolved overloaded function type>’)

Relation between ostream insertion operator and its non-member overload

Why does std::set work with my free function operator<, but not my class member function operator<?

Arrow operator to static, non-member function

Why do compilers now accept to call str() member on a returned std::ostream& from std::stringstream::operator<<()?

std::ostream as optional (!) function parameter

Why ampersand in `std::is_member_function_pointer`?

no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::_Setfill<const char*>')

Why delete a non-member function?

Passing non-static member function as std::function

Use std::function to wrap non-static member function pointer

Why can't I call a non-const member function on an element in an std::set?

Operator << as member function

Why std::function has no function_type or equivalent member type?

Why will std::function call destructor when an object was bound to a member function?

const call operator calling bound non-const member function

c++ postfix / prefix operator overload as non-member function

Static vs. Member Operator Overloads: std::operator<< and std::ostream::operator<<

How to pass ostream operator<< as a function in C++?

Generic std::function member

int showing up as std::basic_ostream<char> in operator==

std :: is_function on member function?

Difference between using << operator with stringsteam and write member function

Member functions called on non-pointer objects with std::function

Why a non-member == operator overloading needed when using a std::pair as a std::unordered_map key

Using std::ostream as argument to a print function

Why does a insertion/extraction operator's overloaded function need ostream/istream argument?

A const std::function wraps a non-const operator() / mutable lambda

Member function vs Operator overloading