There are two approaches to harmonizing the printing of containers with std::cout and related output-stream objects. You can either overload operator<< to print a specific container, or you can arrange it to print a std::pair of iterators. This is demonstrated here:
#include <iostream> #include <vector> #include <utility> // Function declarations int main(); template <typename T> std::ostream &operator<<( std::ostream &out, std::vector<T> const &obj ); template <typename ITR> std::ostream &operator<<( std::ostream &out, std::pair<ITR, ITR> const &obj ); // Function definitions int main() { std::vector<int> data{ 1, 2, 5, 4, 3, 5, 6, 7, 6, 8, 9, 6, 10, 13, 12, 14 }; std::cout << data << std::endl; std::cout << std::make_pair( data.begin(), data.end() ) << std::endl; return 0; } template <typename T> std::ostream &operator<<( std::ostream &out, std::vector<T> const &obj ) { out << "{"; if ( !obj.empty() ) { auto itr{ obj.begin() }; out << *itr++; while ( itr != obj.end() ) { out << ", " << *itr++; } } return out << "}"; } template <typename ITR> std::ostream &operator<<( std::ostream &out, std::pair<ITR, ITR> const &obj ) { out << "{"; if ( obj.first != obj.second ) { auto itr{ obj.first }; out << *itr++; while ( itr != obj.second ) { out << ", " << *itr++; } } return out << "}"; }
This is a nice solution by Jon Hanson that abstracts out the container:
// Function declaration template < typename S, template <typename T, typename ALLOC = std::allocator<T>> class C > std::ostream &operator<<( std::ostream &out, C<S> const &container ); // Function definition template < typename S, template <typename T, typename ALLOC = std::allocator<T>> class C > std::ostream &operator<<( std::ostream &out, C<S> const &container ) { auto itr{ container.begin() }; out << "{"; if ( itr != container.end() ) { out << *itr++; while ( itr != container.end() ) { out << ", " << *itr++; } } return out << "}"; }
The following is an equivalent algorithm that converts a container into a std::string:
#include <sstream> // Function declaration template < typename S, template <typename T, typename ALLOC = std::allocator<T>> class C > std::string to_string( C<S> const &container, std::string separator = ", " ); // Function definition template < typename S, template <typename T, typename ALLOC = std::allocator<T>> class C > std::string to_string( C<S> const &container, std::string separator ) { std::stringstream sstream{}; sstream << "{"; auto itr{ container.begin() }; if ( itr != container.end() ) { sstream << *itr++; while ( itr != container.end() ) { sstream << separator << *itr++; } } sstream << "}"; return sstream.str(); }