Skip to content

Instantly share code, notes, and snippets.

@jflopezfernandez
Last active November 5, 2018 20:25
Show Gist options
  • Save jflopezfernandez/a775e2ee092b4c76a14c749881ba936b to your computer and use it in GitHub Desktop.
Save jflopezfernandez/a775e2ee092b4c76a14c749881ba936b to your computer and use it in GitHub Desktop.
Defining an output operator for a user-defined type
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
namespace IO
{
template <typename CharT, typename Traits = std::char_traits<CharT>>
std::basic_ostream<CharT, Traits>&
endl (std::basic_ostream<CharT, Traits>& outputStream)
{
return outputStream << outputStream.widen('\n');
}
}
class Book {
std::string m_title;
std::string m_author;
unsigned int m_isbn;
std::string m_genre;
public:
Book()
: m_title("Untitled"), m_author("Unknown"), m_isbn(0), m_genre("Unknown")
{ }
Book(const std::string& title, const std::string& author, const unsigned int isbn, const std::string& genre)
: m_title(title), m_author(author), m_isbn(isbn), m_genre(genre)
{ }
std::string title() const noexcept { return m_title; }
std::string author() const noexcept { return m_author; }
unsigned int ISBN() const noexcept { return m_isbn; }
std::string genre() const noexcept { return m_genre; }
void setTitle(const std::string& title) { m_title = title; }
void setAuthor(const std::string& author) { m_author = author; }
void setISBN(const unsigned int isbn) { m_isbn = isbn; }
void setGenre(const std::string& genre) { m_genre = genre; }
};
// This is the traditional output operator implementation most programmers
// use. There are two problems with this. First, because `ostream` is used
// in the signature, the function applies only to streams with the character
// type `char`. If the function is intended only for use in Western Europe or
// in North America, this is no problem. On the other hand, a more general
// version requires only a little extra work, so it should at least be
// considered.
//
// Another problem arises if a field width is set. In this case, the result is
// probably not what might be expected. The field width applies to the
// immediately following write.
//
// Source: The C++ Standard Library, Josuttis (2011) [page. 810-811]
//inline
//std::ostream& operator<<(std::ostream& outputStream, const Book& book)
//{
// outputStream << "Title: " << book.title() << IO::endl;
// outputStream << "Author: " << book.author() << IO::endl;
// outputStream << "ISBN: " << book.ISBN() << IO::endl;
// outputStream << "Genre: " << book.genre() << IO::endl;
//
// return outputStream;
//}
template <typename T, typename Traits>
inline
std::basic_ostream<T, Traits>&
operator<<(std::basic_ostream<T, Traits>& outputStream,
const Book& book)
{
// String stream with the same format, without the
// special field width
std::basic_ostringstream<T, Traits> s;
s.copyfmt(outputStream);
s.width(0);
// Fill String Stream
outputStream << "Title: " << book.title() << IO::endl;
outputStream << "Author: " << book.author() << IO::endl;
outputStream << "ISBN: " << book.ISBN() << IO::endl;
outputStream << "Genre: " << book.genre() << IO::endl;
// Print String Stream
outputStream << s.str();
return outputStream;
}
int main()
{
Book b1 { "The C++ Standard Library", "Nicolas Josuttis", 1, "Computer Science" };
Book b2 { "Little Red Riding Hood", "The Brothers Grimm", 2, "Fairytales" };
Book b3 { "Mastery", "George Leonard", 3, "Self-Improvement" };
const std::vector<Book> books = { b1, b2, b3 };
for (const auto& book : books)
{
std::cout << book << IO::endl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment