Skip to content

Instantly share code, notes, and snippets.

@eskil
Created May 13, 2016 21:04
Show Gist options
  • Save eskil/fc24d6c48810206963fca5f76ba142fb to your computer and use it in GitHub Desktop.
Save eskil/fc24d6c48810206963fca5f76ba142fb to your computer and use it in GitHub Desktop.
#include <sstream>
#include <iostream>
#include <string>
#include <vector>
template<typename InIt, typename Tdelim, typename Tj>
Tj& join (InIt first, InIt last, const Tdelim &d, Tj &j) {
if (first == last)
return j;
InIt next = first;
while (++next != last) {
j << *first << d;
first = next;
}
j << *first;
return j;
}
/**
* @brief Provides output iterator semantics for streams.
*
* This class provides an iterator to write to an ostream. The type Tp is
* the only type written by this iterator and there must be an
* operator<<(Tp) defined.
*
* @param Tp The type to write to the ostream.
* @param CharT The ostream char_type.
* @param Traits The ostream char_traits.
*/
template<typename _Tp, typename _CharT = char,
typename _Traits = std::char_traits<_CharT> >
class ostream_join_iterator
: public std::iterator<std::output_iterator_tag, void, void, void, void>
{
public:
//@{
/// Public typedef
typedef _CharT char_type;
typedef _Traits traits_type;
typedef std::basic_ostream<_CharT, _Traits> ostream_type;
//@}
private:
ostream_type* _M_stream;
const _CharT* _M_string;
bool _M_first;
public:
/// Construct from an ostream.
ostream_join_iterator(ostream_type& __s) : _M_stream(&__s), _M_string(0), _M_first (false) {}
/**
* Construct from an ostream.
*
* The delimiter string @a c is written to the stream after every Tp
* written to the stream. The delimiter is not copied, and thus must
* not be destroyed while this iterator is in use.
*
* @param s Underlying ostream to write to.
* @param c CharT delimiter string to insert.
*/
ostream_join_iterator(ostream_type& __s, const _CharT* __c)
: _M_stream(&__s), _M_string(__c), _M_first (true) { }
/// Copy constructor.
ostream_join_iterator(const ostream_join_iterator& __obj)
: _M_stream(__obj._M_stream), _M_string(__obj._M_string), _M_first (__obj._M_first) { }
/// Writes @a value to underlying ostream using operator<<. If
/// constructed with delimiter string, writes delimiter to ostream.
ostream_join_iterator&
operator=(const _Tp& __value)
{
__glibcxx_requires_cond(_M_stream != 0,
_M_message(__gnu_debug::__msg_output_ostream)
._M_iterator(*this));
if (_M_string && !_M_first) *_M_stream << _M_string;
*_M_stream << __value;
_M_first = false;
return *this;
}
ostream_join_iterator&
operator*()
{ return *this; }
ostream_join_iterator&
operator++()
{ return *this; }
ostream_join_iterator&
operator++(int)
{ return *this; }
};
int main (int argc, char *argv[]) {
std::vector<std::string> strings (argv + 1, argv + argc);
{
std::ostringstream res;
std::cout << join (strings.begin (), strings.end (), ", ", res).str () << "\n";
}
{
std::ostringstream res;
std::copy (strings.begin (), strings.end (), ostream_join_iterator<std::string> (res, ", "));
std:: cout << res.str () << "\n";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment