3

I wish I could just print contents of a set/vector/map by using cout << . It doesn't seem so difficult for the stl designers to implement : Assuming that << is defined for T, << for a container could just iterate through the elements and print them using ofstream << .

Is there an easy way to print them that I dont know of?

If not, Is there an easy solution? I have read at places that extending stl classes is a bad idea. Is that so, and why?

how about defining an something like an overloaded print function? EDIT: I am looking for a recursive function which can handle containers of containers of ... I agree that different people would like different formats, but something overridable is better than nothing

Abhishek Anand
  • 3,789
  • 2
  • 21
  • 29
  • 1
    possible duplicate of [Pretty-print C++ STL containers](http://stackoverflow.com/questions/4850473/pretty-print-c-stl-containers) – ildjarn Feb 16 '12 at 22:08

6 Answers6

5

Probably the easiest way to output an STL container is

std::copy(cont.begin(), cont.end(),
          std::ostream_iterator<Type>(std::cout, " "));

where Type is the type of the elements of cont (e.g. if cont is of type std::vector<int> then Type must be int).

Of course instead of std::cout you can use any ostream.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
celtschk
  • 19,311
  • 3
  • 39
  • 64
  • `Type` is called `container_type::value_type`. – ildjarn Feb 16 '12 at 22:11
  • 1
    @ildjarn: But then you'll still have to specify `container_type` which, unless you are inside a template where the container type is dependend (but then it's `typename container_type::value_type`), will most likely contain `Type` anyway. However, in C++11 you can write `decltype(cont)::value_type` (again, possibly with `typename` in templates). – celtschk Feb 16 '12 at 22:15
3

The easiest eay to dump a container is probably just using std::copy(). For example I typically use something like this:

template <typename C>
std::string format(C const& c) {
    std::ostringstream out;
    out << "[";
    if (!c.empty()) {
        std::copy(c.begin(), --c.end(),
            std::ostream_iterator<typename C::value_type>(out, ", "));
            out << c.back();
    }
    out << "]";
    return out.str();
}

Yes, this doesn't always work but works for my needs. This actually shows one of the problems why there is no output for containers in the standard library: there are many different ways how containers can be formatted. To make matters worse, the formatted output should be readable where thing become real fun. All of this is doable but I'm not aware of a corresponding proposal.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
2

Using Template template parameter makes it easy, in order to make it working for each collection you need both template<class, class...> class X and class... Args as template parameters:

template<class T, template<class, class...> class X, class... Args>
std::ostream& operator <<(std::ostream& os, const X<T, Args...>& objs) {
    os << "{";
    bool commoFlag = false;
    for (auto const& obj : objs) {
        os << (commoFlag ? ", " : "") << obj;
        commoFlag = true;
    }
    os << "}";
    return os;
}

vector<float> f_vec{ 1.3f , 5.134f, 5.78f };
list<char> c_lst{ 'F','O', 'M', 'S', 'A' };
set<int> i_st{ 17,14, -70 };
std::cout << f_vec << std::endl;
std::cout << c_lst << std::endl;
std::cout << i_st << std::endl;

output:

{1.3, 5.134, 5.78}
{F, O, M, S, A}
{-70, 14, 17}
void
  • 7,760
  • 3
  • 25
  • 43
  • Any tips on getting it working on `vector`? This is what I see when trying to use it on a container of strings: https://coliru.stacked-crooked.com/a/7cb4d13bef51f7e5 – Ehtesh Choudhury Jun 30 '23 at 13:13
  • 1
    I see - no Idea :(, sorry. I even tried to specialize it for `const char*` and `string` but didn't work, if you got a working solution feel free to edit the answer. – void Jun 30 '23 at 15:01
  • I don't have an idea yet (not familiar with template C++) but seems like `enable_if` and `is_same` paired with some way to match strings could work. – Ehtesh Choudhury Jul 01 '23 at 22:30
2

In C++11 you can use range-based for:

for (auto& i: container)  cout << i << "  ";
cout << endl;
mikithskegg
  • 806
  • 6
  • 10
1

It doesn't seem so difficult for the stl designers to implement : Assuming that << is defined for T, << for a container could just iterate through the elements and print them using ofstream << .

Of course it is not hard for them. However, ask yourself: Does the format of the output make sense for every client? The standard library is about reuse and genericity. Coupling containers with some arbitrary output formatting rules makes them less generic for the sake of only some.

The recommended solution therefore is to provide your own operator<<(std::ostream &, T) and/or to take other generic algorithms, as found in e.g. <algorithms>.

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
0

Are you looking something like this?

#include <iostream>
#include <set>

template <typename T>
std::ostream& operator<< (std::ostream& os, const std::set<T>& s)
{
    for( auto i: s ) {
        os << i << " ";
    }
    return os;
}

Then you just may use it this way:

std::set<int> my_set = { 11, 12, 13 };

std::cout << my_set << std::endl;
Jacques
  • 301
  • 2
  • 13