Consider the following:
std::cout << '\\n' << "Added: " << book << std::endl;
// Output
Added: "what if?" by Randall Munroe
This statement contains multiple << operators that are chained in a single instruction. The insertion operator (<<) operators on a C-style string literal, an escape sequence, a class object and a function.
- How does
<<know how to interact with each unique type? - How do all of these instructions resolve into a clean
std::coutstatement
The answer comes down to two C++ features working together in perfect unison.
1. What do operators return?
When we do 22 + 4 in maths, the operands (22, 4) are manipulated by an operator (+). The result is a new value.
In C++, this new output value that arises from an operation is called a return value. This can be used as an operand as part of a new operation. This is what makes chaining possible — each operation feeds its result into the next.
2. Operator overloading
The example at the beginning of the page is from my library management system program. Book knows how to interact with << since the insertion operator is overloaded to work with Book objects.
// The overloaded function returns an std::ostream
std::ostream& operator <<(std::ostream& outStream, const Book& book) {
outStream << "\\"" << book.m_title << "\\" by " << book.m_author;
// Fancy logic ...
return outStream;
}
Since it returns a std::ostream, we can use operator chaining to operate on it again via <<.
The standard library overloads << to operate on std::ostream, char, int.
Takeaway
Operator overloading can be used to chain an operation to operate on different types leading to clean code like: std::cout << '\\n' << "Added: " << book << std::endl;