HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Comma-formatted STL vectors

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
formattedstlvectorscomma

Problem

I move back and forth between Python and C++ and I often need a nice/quick way to output STL objects to the screen for debugging purposes. I'd like the output to match the output of a comparable Python object, thus I have different templates for vectors, sets, etc...

Is this the best way to go about this?

template 
ostream& operator &A) {
  if(A.empty()) 
    return s ::const_iterator itr_penultimate = --A.end();
  typename vector::const_iterator itr = A.begin();

  while(itr != itr_penultimate) {
    s << *itr << ", ";
    itr++;
  }
  return s << *itr << "]";
}

Solution

The above answer is fine.

The only problem I have is the extra ',' in the output:

std::cout (std::cout, ", "));
std::cout << " ]\n";


Generates the output:

[ 1, 2, 3, 4, 5, 6,  ]
                  ^  extra comma


You can get around this with some extra work.

auto end = data.end();
if (!data.empty()) { --end;}
std::cout (std::cout, ", "));
if (!data.empty()) {std::cout << *end;}
std::cout << " ]\n";


Generates the output:

[ 1, 2, 3, 4, 5, 6 ]


This is better but it sort of defeats the purpose of using algorithms.

If we had used the loop it would look like this:

std::cout << "[";
for(auto loop = data.begin(); loop != data.end(); ++loop)
{
     std::cout << *itr << ", ";
}
std::cout << "]";


Of course this has the same problem as the first version of the algorithm above. So if we take that into account you can re-write like this:

std::cout << "[";
auto begin = data.begin();
if (!data.empty) {std::cout << *begin;++begin}
for(auto loop = begin; loop != data.end(); ++loop)
{
     std::cout << ", " << *loop;
}
std::cout << "]";


Now it works. And because it only use one test on empty is better than the altered algorithm version in my opinion. So what we really need is a version of the output iterator that does the above.

template
class PrefexOutputIterator
{
    std::ostream&       ostream;
    std::string         prefix;
    bool                first;
    public:

    typedef std::size_t                 difference_type;
    typedef T                           value_type;
    typedef T*                          pointer;
    typedef T                           reference;
    typedef std::output_iterator_tag    iterator_category;

        PrefexOutputIterator(std::ostream& o,std::string const& p = ""): ostream(o), prefix(p), first(true) {}

        PrefexOutputIterator& operator*()       {return *this;}
        PrefexOutputIterator& operator++()      {return *this;}
        PrefexOutputIterator& operator++(int)   {return *this;}

        void operator=(T const& value)
        {
            if (first)      {ostream << value;first = false;}
            else            {ostream << prefix << value;}
        }
};


Now we can use this and get the output we want:

std::cout (std::cout, ", "));
std::cout << "]";


The output is:

[1, 2, 3, 4, 5, 6]


Nowadays though I seem to be using a lot of Json.
So now I use this template librrys: https://github.com/Loki-Astari/ThorsSerializer

using ThorsAnvil::Serialize::jsonExport;
using ThorsAnvil::Serialize::jsonImport;

std::cout > jsonImport(data);         // Reads a json array into an array.

Code Snippets

std::cout << "[ ";
std::copy(data.begin(), data.end(), std::ostream_iterator<int>(std::cout, ", "));
std::cout << " ]\n";
[ 1, 2, 3, 4, 5, 6,  ]
                  ^  extra comma
auto end = data.end();
if (!data.empty()) { --end;}
std::cout << "[ ";
std::copy(data.begin(), end, std::ostream_iterator<int>(std::cout, ", "));
if (!data.empty()) {std::cout << *end;}
std::cout << " ]\n";
[ 1, 2, 3, 4, 5, 6 ]
std::cout << "[";
for(auto loop = data.begin(); loop != data.end(); ++loop)
{
     std::cout << *itr << ", ";
}
std::cout << "]";

Context

StackExchange Code Review Q#30132, answer score: 8

Revisions (0)

No revisions yet.