I've previously posted this on Stack Overflow, and am considering submitting it to Boost for wider distribution, but thought perhaps it would be best to put it up here for peer review first, and see whether there are clear improvements that can be made first.
// infix_iterator.h
//
#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:
// We don't print the delimiter the first time. After that,
// each invocation prints the delimiter *before* the item, not
// after. As a result, we only get delimiters *between* items,
// not after every one.
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
This is (at least intended to be) pretty much a drop-in replacement for std::ostream_iterator
, the sole difference being that (at least in normal use) it only prints out delimiters between items instead of after every item. Code using it looks something like:
#include "infix_iterator.h"
std::vector<int> numbers = {1, 2, 3, 4};
std::copy(begin(numbers), end(numbers),
infix_ostream_iterator<int>(std::cout, ", "));
The motivation for this is pretty simple -- with a std::ostream_iterator
, your list would come out like 1, 2, 3, 4,
, but with the infix_iterator, it comes out as 1, 2, 3, 4
.
As a side-note, although I've used a couple of C++11 features in this demo code, I believe the iterator itself should be fine with C++03 -- though if somebody sees anything that would be a problem for a compiler without C++11 support, I'd like to hear about that too.
Edit: In case anybody cares, here's the new version incorporating input from both @Konrad and @Loki. Thanks to both of you.
// infix_iterator.h
#if !defined(INFIX_ITERATOR_H_)
#define INFIX_ITERATOR_H_
#include <ostream>
#include <iterator>
#include <string>
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;
std::basic_string<charT> delimiter;
std::basic_string<charT> real_delim;
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)
{}
infix_ostream_iterator(ostream_type &s, charT const *d)
: os(&s),
real_delim(d)
{}
infix_ostream_iterator<T, charT, traits> &operator=(T const &item)
{
*os << delimiter << item;
delimiter = real_delim;
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
charT const *d
instead of aconst std::basic_string<charT>&
? \$\endgroup\$std::ostream_iterator
? \$\endgroup\$infix_iterator
norinfix_ostream_iterator
in Boost. \$\endgroup\$