The compiler collects a set of functions named operator<<
(or operator>>
) from a variety of places:
- current scope
- members of the left-hand operand and its base classes
- namespace of the left-hand operand (which may be defined inside the class using the
friend
keyword)
- namespace of the right-hand operand (which may be defined inside the class using the
friend
keyword)
- built-in versions that apply to primitive integral types
It then performs overload resolution in the same way as when calling a function with an "ordinary" name in order to determine which of these to use. Implicit conversions are considered during overload resolution, but generally providing iostream support for a data type includes providing a match that is more direct than an implicit conversion to string would be (for example, reference conversions are better).
Since the left-hand operand here is std::cout
(or std::cin
), you don't have much control over its members or its namespace. And you cannot change the built-in versions. But that still gives you several ways to add support for new types -- as the program author, use the current scope, and as a library author, use the namespace of the class you write.