Search code examples
c++pretty-printseparator

How can I print a list of elements separated by commas?


I know how to do this in other languages, but not in C++, which I am forced to use here.

I have a set of strings (keywords) that I'm printing to out as a list, and the strings need a comma between them, but not a trailing comma. In Java, for instance, I would use a StringBuilder and just delete the comma off the end after I've built my string. How can I do it in C++?

auto iter = keywords.begin();
for (iter; iter != keywords.end( ); iter++ )
{
    out << *iter << ", ";
}
out << endl;

I initially tried inserting the following block to do it (moving the comma printing here):

if (iter++ != keywords.end())
    out << ", ";
iter--;

Solution

  • Use an infix_iterator:

    // infix_iterator.h 
    // 
    // Lifted from Jerry Coffin's 's prefix_ostream_iterator 
    #if !defined(INFIX_ITERATOR_H_) 
    #define  INFIX_ITERATOR_H_ 
    #include <ostream> 
    #include <iterator> 
    template <class T, 
              class charT=char, 
              class traits=std::char_traits<charT> > 
    class infix_ostream_iterator : 
        public std::iterator<std::output_iterator_tag,void,void,void,void> 
    { 
        std::basic_ostream<charT,traits> *os; 
        charT const* delimiter; 
        bool first_elem; 
    public: 
        typedef charT char_type; 
        typedef traits traits_type; 
        typedef std::basic_ostream<charT,traits> ostream_type; 
        infix_ostream_iterator(ostream_type& s) 
            : os(&s),delimiter(0), first_elem(true) 
        {} 
        infix_ostream_iterator(ostream_type& s, charT const *d) 
            : os(&s),delimiter(d), first_elem(true) 
        {} 
        infix_ostream_iterator<T,charT,traits>& operator=(T const &item) 
        { 
            // Here's the only real change from ostream_iterator: 
            // Normally, the '*os << item;' would come before the 'if'. 
            if (!first_elem && delimiter != 0) 
                *os << delimiter; 
            *os << item; 
            first_elem = false; 
            return *this; 
        } 
        infix_ostream_iterator<T,charT,traits> &operator*() { 
            return *this; 
        } 
        infix_ostream_iterator<T,charT,traits> &operator++() { 
            return *this; 
        } 
        infix_ostream_iterator<T,charT,traits> &operator++(int) { 
            return *this; 
        } 
    };     
    #endif 
    

    Usage would be something like:

    #include "infix_iterator.h"
    
    // ...
    std::copy(keywords.begin(), keywords.end(), infix_iterator(out, ","));