Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing Any STL Container

How would you go about writing a library that, when included, it overloads the << operator for any* existing STL container?

  • Except adaptors like stack and queue, since you cannot iterate through them.

The one self-imposed requirement is that it mustn't include any of the containers' header files. That would bloat the final executable unnecessarily. It makes more sense to include this header after the containers' that I would like to work with. This restriction implies the use of templates or macros.

I'm looking for advice and pointers, so, please, don't just post fully working code that can do this! Implementing this myself is part of the learning process. Small snippets of code that demonstrate how certain things work are welcome.

What I did up to this point:

I have overloaded the << operator for every container with a different template signature. The problem that I have run into with this approach is, that there are containers that have the same number of template parameters, but some contain std::pair-s, others single values. More precisely, this is the case of std::map & std::multimap vs std::unordered_set & std::unordered_multiset.

This collision forces me to either implement a non-template version of one of the pairs, or to come up with a way to differentiate between std::pair-s and single values. I don't really know how to go about doing the second one, though. The reason because I'm not "how to do that" directly is that I'm starting to believe that this could be avoided entirely with a better overall design.

Thank you in advance!



What worked for me:

  1. Overload operator<< for std::pair
  2. Overload operator<< for every STL container with different template arguments

    Note:

    1. template <typename T1> and template <typename T1, typename T2> are different
    2. template <typename T1, typename T2> and template <typename T1, size_t T2> are different
    3. template <typename T1, typename T2> and template <typename C1, typename C2> are NOT different
  3. Put them in a namespace to make sure that your operators won't collide with any other operators that you might need in the future.


Use "templates in templates", so for example a function would look like:

template <typename Type, template <typename TYPE> class TClass>
void func(TClass<Type>& tc) {
    if (tc.somethingTrue())
        tc.doStuff();
}
like image 667
mrDudePerson Avatar asked Dec 02 '15 21:12

mrDudePerson


People also ask

Are STL containers thread safe?

The SGI implementation of STL is thread-safe only in the sense that simultaneous accesses to distinct containers are safe, and simultaneous read accesses to to shared containers are safe.

What is Value_type C++?

The priority_queue :: value_type method is a builtin function in C++ STL which represents the type of object stored as an element in a priority_queue. It acts as a synonym for the template parameter.


2 Answers

You could overload operator<< as a template that takes a template template argument (i.e., any container).

Then you could provide two overloads of a template function (e.g., print) that the one overload would specialize on std::pair.

template<typename T>
std::ostream& print(std::ostream &out, T const &val) { 
  return (out << val << " ");
}

template<typename T1, typename T2>
std::ostream& print(std::ostream &out, std::pair<T1, T2> const &val) { 
  return (out << "{" << val.first << " " << val.second << "} ");
}

template<template<typename, typename...> class TT, typename... Args>
std::ostream& operator<<(std::ostream &out, TT<Args...> const &cont) {
  for(auto&& elem : cont) print(out, elem);
  return out;
}

LIVE DEMO

like image 186
101010 Avatar answered Oct 19 '22 08:10

101010


A very simple attempt at this problem is something like:

template<typename T>  
void print_container(std::ostream& os, const T& container, const std::string& delimiter)  
{  
    std::copy(std::begin(container),   
              std::end(container),   
              std::ostream_iterator<typename T::value_type>(os, delimiter.c_str())); 
}  
like image 27
Paul Evans Avatar answered Oct 19 '22 08:10

Paul Evans