fork download
  1. #include <iostream>
  2. #include <iterator>
  3. #include <type_traits>
  4. #include <vector>
  5. #include <deque>
  6. #include <algorithm>
  7. #include <string>
  8.  
  9. // This works similar to ostream_iterator, but doesn't print a delimiter after the final item
  10. template<typename T, typename TChar = char, typename TCharTraits = std::char_traits<TChar> >
  11. class pretty_ostream_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void> {
  12. public:
  13. typedef TChar char_type;
  14. typedef TCharTraits traits_type;
  15. typedef std::basic_ostream<TChar, TCharTraits> ostream_type;
  16. pretty_ostream_iterator(ostream_type &stream, const char_type *delim = NULL)
  17. : _stream(&stream), _delim(delim), _insertDelim(false)
  18. { }
  19. pretty_ostream_iterator<T, TChar, TCharTraits>& operator=(const T &value) {
  20. if( _delim != NULL ) {
  21. // Don't insert a delimiter if this is the first time the function is called
  22. if( _insertDelim )
  23. (*_stream) << _delim;
  24. else
  25. _insertDelim = true;
  26. }
  27. (*_stream) << value;
  28. return *this;
  29. }
  30. pretty_ostream_iterator<T, TChar, TCharTraits>& operator*() {
  31. return *this;
  32. }
  33. pretty_ostream_iterator<T, TChar, TCharTraits>& operator++() {
  34. return *this;
  35. }
  36. pretty_ostream_iterator<T, TChar, TCharTraits>& operator++(int) {
  37. return *this;
  38. }
  39. private:
  40. ostream_type *_stream;
  41. const char_type *_delim;
  42. bool _insertDelim;
  43. };
  44. #if _MSC_VER >= 1400
  45. // Declare pretty_ostream_iterator as checked
  46. template<typename T, typename TChar, typename TCharTraits>
  47. struct std::_Is_checked_helper<pretty_ostream_iterator<T, TChar, TCharTraits> >
  48. : public std::tr1::true_type
  49. { };
  50. #endif // _MSC_VER >= 1400
  51.  
  52. //////////////////////////////////////////////////////////////////////////
  53. //////////////////////Editor's comment: this results in undefined behavior
  54. //////////////////////////////////////////////////////////////////////////
  55. namespace std {
  56. // Pre-declarations of container types so we don't actually have to include the relevant headers if not needed, speeding up compilation time.
  57. // These aren't necessary if you do actually include the headers.
  58. template<typename T, typename TAllocator> class vector;
  59. template<typename T, typename TAllocator> class list;
  60. template<typename T, typename TTraits, typename TAllocator> class set;
  61. template<typename TKey, typename TValue, typename TTraits, typename TAllocator> class map;
  62. }
  63. // Basic is_container template; specialize to derive from std::true_type for all desired container types
  64. template<typename T> struct is_container : public std::false_type { };
  65.  
  66. // Mark vector as a container
  67. template<typename T, typename TAllocator>
  68. struct is_container<std::vector<T, TAllocator> > : public std::true_type { };
  69. // Mark list as a container
  70. template<typename T, typename TAllocator>
  71. struct is_container<std::list<T, TAllocator> > : public std::true_type { };
  72. // Mark set as a container
  73. template<typename T, typename TTraits, typename TAllocator>
  74. struct is_container<std::set<T, TTraits, TAllocator> > : public std::true_type { };
  75. // Mark map as a container
  76. template<typename TKey, typename TValue, typename TTraits, typename TAllocator>
  77. struct is_container<std::map<TKey, TValue, TTraits, TAllocator> > : public std::true_type { };
  78. // Mark deque as a container
  79. template<typename T, typename TAllocator>
  80. struct is_container<std::deque<T, TAllocator>> : public std::true_type { };
  81.  
  82.  
  83. //////////////////////////////////////////////////////////////////////////
  84. //////////////////////Editor's comment: My changes begin here
  85. //////////////////////////////////////////////////////////////////////////
  86. template<typename TChar = char, typename TCharTraits = std::char_traits<TChar>>
  87. struct delimiters_v2 {
  88. typedef std::basic_string<TChar, TCharTraits> delimiter_type;
  89. delimiters_v2(const delimiter_type& prefix_, const delimiter_type& delimiter_, const delimiter_type& postfix_)
  90. : prefix(prefix_), delimiter(delimiter_), postfix(postfix_)
  91. { }
  92.  
  93. //Since we're passing this around as a value type, trusting the user to provide static strings isn't safe
  94. std::basic_string<TChar, TCharTraits> prefix;
  95. std::basic_string<TChar, TCharTraits> delimiter;
  96. std::basic_string<TChar, TCharTraits> postfix;
  97. };
  98.  
  99. //This is the class users are meant to specialize in order to get special behavior for a given type [example below]
  100. template<typename Container, typename TChar = char, typename TCharTraits = std::char_traits<TChar>>
  101. struct default_delimiters_v2 {
  102. static delimiters_v2<TChar, TCharTraits> get() {
  103. return delimiters_v2<TChar, TCharTraits>("(", ", ", ")");
  104. }
  105. };
  106.  
  107. template<typename Container>
  108. struct default_delimiters_v2<Container, wchar_t> {
  109. static delimiters_v2<wchar_t> get() {
  110. return delimiters_v2<wchar_t>(L"(", L", ", L")");
  111. }
  112. };
  113.  
  114. //Just a copy of the original helper class, with the delimiter parameter removed.
  115. //Instead, the constructor takes a delimiter argument that defaults to default_delimiters_v2<...>::get()
  116. template<typename T, typename TChar = char, typename TCharTraits = std::char_traits<TChar> >
  117. struct print_container_helper_v2 {
  118. typedef TChar char_type;
  119. typedef delimiters_v2<TChar, TCharTraits> delimiter_type;
  120. typedef std::basic_ostream<TChar, TCharTraits>& ostream_type;
  121. print_container_helper_v2(const T& container, const delimiter_type& delims = default_delimiters_v2<T, TChar>::get())
  122. : container_(container), delims_(delims)
  123. { }
  124.  
  125. void operator()(ostream_type& stream) const {
  126. //I removed the checks against null here, because I'm pretty sure the `basic_string` overload takes care of that case
  127. stream << delims_.prefix;
  128. std::copy(container_.begin(), container_.end(),
  129. pretty_ostream_iterator<typename T::value_type, TChar, TCharTraits>(stream, delims_.delimiter.c_str()));
  130. stream << delims_.postfix;
  131. }
  132.  
  133. private:
  134. const T& container_;
  135. delimiter_type delims_;
  136. };
  137.  
  138.  
  139. //////////////////////////////////////////////////////////////////////////
  140. //////////////////////Editor's comment: These are just a few helper functions to allow template parameter deduction
  141. //////////////////////////////////////////////////////////////////////////
  142. template<typename T, typename TChar, typename TCharTraits>
  143. print_container_helper_v2<T, TChar, TCharTraits>
  144. print_container_function_v2(const T& c,
  145. const delimiters_v2<TChar, TCharTraits>& d)
  146. {
  147. return print_container_helper_v2<T, TChar, TCharTraits>(c, d);
  148. }
  149.  
  150. template<typename T>
  151. print_container_helper_v2<T> print_container_function_v2(const T& c) {
  152. return print_container_function_v2(c, default_delimiters_v2<T>::get());
  153. }
  154.  
  155.  
  156. //////////////////////////////////////////////////////////////////////////
  157. //////////////////////Editor's comment: An example of how to customize the behavior for a specific type
  158. //////////////////////////////////////////////////////////////////////////
  159. template<typename T, typename TAlloc>
  160. struct default_delimiters_v2<std::deque<T, TAlloc>> {
  161. static delimiters_v2<> get() {
  162. return delimiters_v2<>("<", " ", ">");
  163. }
  164. };
  165.  
  166. template<typename T, typename TChar, typename TCharTraits>
  167. std::basic_ostream<TChar, TCharTraits>& operator<<(std::basic_ostream<TChar, TCharTraits> &stream,
  168. const print_container_helper_v2<T, TChar> &helper) {
  169. helper(stream);
  170. return stream;
  171. }
  172.  
  173. template<typename T, typename TChar, typename TCharTraits>
  174. typename std::enable_if<is_container<T>::value, std::basic_ostream<TChar, TCharTraits>&>::type
  175. operator<<(std::basic_ostream<TChar, TCharTraits> &stream, const T &container) {
  176. stream << print_container_helper_v2<T, TChar, TCharTraits>(container);
  177. return stream;
  178. }
  179.  
  180. // Used by the sample below to generate some values
  181. struct fibonacci {
  182. fibonacci() : f1(0), f2(1) { }
  183. int operator()() {
  184. int r = f1 + f2;
  185. f1 = f2;
  186. f2 = r;
  187. return f1;
  188. }
  189. private:
  190. int f1;
  191. int f2;
  192. };
  193.  
  194. int main() {
  195. std::vector<int> v;
  196. std::generate_n(std::back_inserter(v), 10, fibonacci());
  197. std::cout << v << std::endl;
  198.  
  199. std::deque<int> d;
  200. std::generate_n(std::back_inserter(d), 10, fibonacci());
  201. std::cout << d << std::endl;
  202.  
  203. std::cout << "Using helper struct: " << std::endl;
  204. std::cout << print_container_helper_v2<std::deque<int>>(d) << std::endl;
  205. std::cout << print_container_helper_v2<std::deque<int>>(d, delimiters_v2<>("?", "-", "&")) << std::endl;
  206.  
  207. std::cout << "Using Helper Functions" << std::endl;
  208. std::cout << print_container_function_v2(v) << std::endl;;
  209. std::cout << print_container_function_v2(v, delimiters_v2<>("^", "_", "^")) << std::endl;
  210. std::cout << std::endl;
  211. }
Success #stdin #stdout 0s 2972KB
stdin
Standard input is empty
stdout
(1, 1, 2, 3, 5, 8, 13, 21, 34, 55)
<1 1 2 3 5 8 13 21 34 55>
Using helper struct: 
<1 1 2 3 5 8 13 21 34 55>
?1-1-2-3-5-8-13-21-34-55&
Using Helper Functions
(1, 1, 2, 3, 5, 8, 13, 21, 34, 55)
^1_1_2_3_5_8_13_21_34_55^