What is the most elegant way, in your opinion, to print to std::cout
using std::ostream_iterator
in C++11 and avoid printing a trailing delimeter?
The object I'm printing has bidirectional iterators, but not random access iterators.
std::list<double> x{1,2,3,4,5,6};
std::copy(x.begin(), std::prev(x.end()),
std::ostream_iterator<int>(std::cout, ",") );
if ( x.size() != 0 )
std::cout << *(--x.end()) << std::endl;
Here's one of my favorites, but it doesn't use std::ostream_iterator
:
#include <iterator>
#include <string>
#include <iosfwd>
template <class C>
auto
print(std::ostream& os, const C& c,
const std::string& delim = std::string(", "),
const std::string& open_brace = std::string("{"),
const std::string& close_brace = std::string("}")
) -> decltype(std::begin(c), std::end(c), os)
{
os << open_brace;
auto i = std::begin(c);
auto e = std::end(c);
if (i != e)
{
os << *i;
for (++i; i != e; ++i)
os << delim << *i;
}
os << close_brace;
return os;
}
#include <list>
#include <iostream>
int main()
{
std::list<double> x{1,2,3,4,5,6};
print(std::cout, x) << '\n';
}
{1, 2, 3, 4, 5, 6}
Update
Oliver goaded me into a challenge I couldn't resist. :-)
#include <iterator>
#include <string>
#include <iosfwd>
namespace my {
template <class C>
auto
print(std::ostream& os, const C& c,
const std::string& delim = std::string(", "),
const std::string& open_brace = std::string("{"),
const std::string& close_brace = std::string("}")
) -> decltype(std::begin(c), std::end(c), os);
template <class C,
typename std::enable_if
<
!std::is_same<C, std::string>::value,
bool>::type = false
>
inline
auto
operator<< (std::ostream& os, const C& c) -> decltype(print(os, c))
{
return print(os, c);
}
template <class C>
auto
print(std::ostream& os, const C& c,
const std::string& delim,
const std::string& open_brace,
const std::string& close_brace
) -> decltype(std::begin(c), std::end(c), os)
{
os << open_brace;
auto i = std::begin(c);
auto e = std::end(c);
if (i != e)
{
os << *i;
for (++i; i != e; ++i)
os << delim << *i;
}
os << close_brace;
return os;
}
}
#include <list>
#include <forward_list>
#include <iostream>
int main()
{
std::forward_list<std::list<double>> x{{}, {3, 2, 1}, {1,2,3,4,5,6}};
my::print(std::cout, x) << '\n';
}
{{}, {3, 2, 1}, {1, 2, 3, 4, 5, 6}}
It isn't perfect, but it was fun. :-) There's probably a better way to do it that would propagate the custom delimiter and braces more faithfully.
Simply move back your cursor by:
std::cout << "\b";
and then overwrite the delimiter.
C++14 - unfortunately requires in/out stream:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <list>
int main()
{
std::list<double> x{1,2,3,4,5,6};
std::stringstream sstr;
std::transform(x.begin(), x.end(), std::ostream_iterator<std::string>(sstr), [&](auto c){
return (sstr.rdbuf()->in_avail() ? "," : "") + std::to_string(c);
});
std::cout << sstr.str() << std::endl;
}
live
Since C++17 there will be ostream_joiner which will fix this problem:
#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>
int main()
{
int i[] = {1, 2, 3, 4, 5};
std::copy(std::begin(i),
std::end(i),
std::experimental::make_ostream_joiner(std::cout, ", "));
}
live
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With