How to change delimiter's position?
This example :
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
int v[] = { 1, 2, 3 };
std::copy( &v[0], &v[3], std::ostream_iterator< int >( std::cout, "\n " ) );
}
produces next output :
1
2
3
Is there a way to change the example to make it produce next output?
1
2
3
PS I 开发者_如何学Cknow I could use the for loop, but I am interested in a solution that uses algorithms and iterators.
There is no way to do this with std::ostream_iterator
. (IMHO, there should
be, but it's not there.) If you don't mind writing an extra small
function or class,
you can use std::transform
, e.g.:
struct FormatString
{
std::string operator()( std::string const& original ) const
{
return ' ' + original + '\n';
}
};
// ...
std::transform(
v.begin(), v.end(),
std::ostream_iterator<std::string>( std::cout ),
FormatString() );
If you have C++11, you can use a lambda for the FormatString
.
I find the need for this occurs often enough that I've written a
PatsubstTransformer
—a functional object which basically
implements the $(patsubst...)
function of GNU make. So I would just
have to write:
std::transform(
v.begin(), v.end(),
std::ostream_iterator<std::string>( std::cout ),
PatsubstTransformer( "%", " %\n" ) );
I find I use this a lot. (I also find using std::transform
more
appropriate than std::copy
, since what I'm outputting is a
transformation.)
If you want to use C++11 you can use a lambda.
e.g like this:
int v[] = { 1, 2, 3};
std::for_each( &v[0], &v[3], [](int i){ std::cout << " " << i << "\n";} );
Use std::cout << " "
, instead of std::cout
as:
std::copy(v, v+3, std::ostream_iterator<int>(std::cout << " ", "\n " ) );
Here the expression std::cout << " "
first evaluates which prints a single space to the output, and the evaluated value which is std::ostream&
gets passed to std::ostream_iterator
Now the output will be aligned correctly:
1
2
3
Working code : http://www.ideone.com/kSdpk
By the way, don't write &v[3]
. That invokes Undefined bevahior. Write v+3
.
Output a single space before the std::copy
.
No, not really. ostream_iterator
isn't configurable like that.
So you'll have to use the pre-space "workaround" as found in other answers, and manually chop off that final line.
BTW It's been noted that &v[3]
, strictly speaking, invokes undefined behaviour due to the implicit dereference in the sub-expression v[3]
. Prefer &v[0]+3
(or just v+3
) — "having" a pointer to one-past-the-end of an array is okay, as long as it's not dereferenced.
You could make your own kind of ostream_iterator
that does this, as the following example demonstrates.
Yes, it's verbose; however, you can also change it around however you like to suit your changing needs:
#include <iostream>
#include <iterator>
#include <algorithm>
template <class T, class charT = char, class traits = std::char_traits<charT> >
struct ostream_iterator_x
: std::iterator<std::output_iterator_tag, void, void, void, void> {
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;
ostream_iterator_x(ostream_type& s, const charT* pre = 0, const charT* post = 0)
: s(s)
, pre(pre)
, post(post) {};
ostream_iterator_x(const ostream_iterator_x& x)
: s(x.s)
, pre(x.pre)
, post(x.post) {};
~ostream_iterator_x() {}
ostream_iterator_x& operator=(const T& value) {
if (pre != 0) s << pre;
s << value;
if (post != 0) s << post;
return *this;
}
ostream_iterator_x& operator*() { return *this; }
ostream_iterator_x& operator++() { return *this; }
ostream_iterator_x& operator++(int) { return *this; }
private:
ostream_type& s;
const charT* pre;
const charT* post;
};
int main()
{
int v[] = { 1, 2, 3 };
std::copy(v, v+3, ostream_iterator_x<int>(std::cout, " ", "\n"));
}
// Output:
// 1
// 2
// 3
(I used [n3290: 24.6/2]
to determine the members and base-specification required for this to work and to be standard-compliant.)
精彩评论