// // Created by AdrianFreed on 9/24/20. // << overloads for printing containers // requires C++17 // #ifndef CONTAINER_O_STREAM_H #define CONTAINER_O_STREAM_H #include <iostream> #include <array> #include <vector> #include <set> #include <unordered_set> #include <map> #include <unordered_map> #include <tuple> #include <deque> #include <list> #include <forward_list> //Pairs template<typename TA, typename TB> auto &operator;<<(std::ostream &os;, const std::pair<TA, TB> &p;) { os << '(' << p.first << ',' << p.second << ')'; return os; } //Tuples // variadic template metaprogram to iterate over the tuple elements // requires C++17, replace with messier folds if using earlier version template<size_t I = 0, typename... Tp> void tuple_element_print(const std::tuple<Tp...> &t;, std::ostream &os;) { os << std::get<I>(t); if constexpr(I + 1 != sizeof...(Tp)) { os << ", "; tuple_element_print<I + 1>(t, os); } } template<typename ...Types> auto &operator;<<(std::ostream &os;, const std::tuple<Types ...> &t;) { os << "(T "; tuple_element_print(t, os); os << ")"; return os; } namespace CONTAINERSTREAM { //Maps template<typename C> std::ostream &output;(std::ostream &os;, C &v;, const char *first, const char *separator, const char *last) { os << first; for (auto it = v.cbegin(); it != v.cend(); ++it) { os << it->first << ':' << it->second; if (std::next(it) != v.cend()) os << separator; } os << last; return os; } } template<typename T, typename Tbis> std::ostream &operator;<<(std::ostream &os;, const std::unordered_map<T, Tbis> &v;) { return CONTAINERSTREAM::output(os, v, "[Unorderedmap ", ", ", "]"); } template<typename T, typename Tbis> std::ostream &operator;<<(std::ostream &os;, const std::map<T, Tbis> &v;) { return CONTAINERSTREAM::output(os, v, "[Map ", ", ", "]"); } template<typename T, typename Tbis> std::ostream &operator;<<(std::ostream &os;, const std::multimap<T, Tbis> &v;) { return CONTAINERSTREAM::output(os, v, "[Multimap ", ", ", "]"); } namespace CONTAINERSTREAM { // The Rest template<typename C> std::ostream & vectorarrayoutput(std::ostream &os;, C &v;, const char *first, const char *separator, const char *last) { os << first; for (auto it = v.cbegin(); it != v.cend(); ++it) { os << *it; if (std::next(it) != v.cend()) os << separator; } os << last; return os; } } // There may appear to be a lot of repetition in these functions // The idea behind that is that you are invited to change the styling of // each separator and bracket according to your own aesthetics or conventions template<typename T, std::size_t N> auto &operator;<<(std::ostream &os;, const std::array<T, N> &a;) { return CONTAINERSTREAM::vectorarrayoutput(os, a, "[Array ", ", ", "]"); } template<typename T> std::ostream &operator;<<(std::ostream &os;, const std::vector<T> &v;) { return CONTAINERSTREAM::vectorarrayoutput(os, v, "[Vector ", ", ", "]"); } template<typename T> std::ostream &operator;<<(std::ostream &os;, const std::set<T> &v;) { return CONTAINERSTREAM::vectorarrayoutput(os, v, "[Set ", ", ", "]"); } template<typename T> std::ostream &operator;<<(std::ostream &os;, const std::multiset<T> &v;) { return CONTAINERSTREAM::vectorarrayoutput(os, v, "[Multiset ", ", ", "]"); } template<typename T> std::ostream &operator;<<(std::ostream &os;, const std::list<T> &l;) { return CONTAINERSTREAM::vectorarrayoutput(os, l, "(List ", ", ", ")"); } template<typename T> std::ostream &operator;<<(std::ostream &os;, const std::forward_list<T> &l;) { return CONTAINERSTREAM::vectorarrayoutput(os, l, "(ForwardList ", ", ", ")"); } template<typename T> std::ostream &operator;<<(std::ostream &os;, const std::deque<T> &d;) { return CONTAINERSTREAM::vectorarrayoutput(os, d, "(Deque ", ", ", ")"); } #endif //TEST_CONTAINER_O_STREAM_H
Links:
[1] https://github.com/adrianfreed/containerostream
[2] http://www.adrianfreed.com/category/quality/exemplary
[3] http://www.adrianfreed.com/category/technique/programming
[4] http://www.adrianfreed.com/taxonomy/term/18