Question

I want to use std::copy and std::ostream_iterator to print out the string within a vector as a coma separated list between parenthesis. So I have to deal with the issue of removing the ", " after the last element.

I have tried this:

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>

int main() {

    std::vector<std::string> v;
    v.push_back("a");
    v.push_back("b");
    v.push_back("c");

    std::stringstream os;
    os << '(';
    std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>(os, ", "));
    os.seekp(-2, std::ios_base::cur);
    os << ')';

    std::cout << os.str() << ".";

    return 0;
}

Output:

(a, b, c) .
         ^

But the output I get has an extra white space character after the closing parenthesis, because seekp just moves the writing position but doesn't remove the written characters.

Is there a way to remove that last character or write an EOF?

Was it helpful?

Solution

How about not writing the extra ", " at the end in the first place...

if(!v.empty())
{
   std::copy(v.begin(), v.end()-1, std::ostream_iterator<std::string>(os, ", "));
   os << v.back();
}

OTHER TIPS

You are not just removing the characters when you use seekp, you are setting the current cursor. Your next statement will overwrite that character, but you still have the subsequent characters in the buffer already. There are a couple of ways to deal with that:

Don't output the full pattern:

std::ostringstream os;
os << '(';
std::copy(v.begin(), v.end() - 1, std::ostream_iterator<std::string>(os, ", "));
if (v.size() > 1) // or (!v.empty())
    os << *(v.end() - 1) << ')';

This will print all but the last character of your vector with the pattern (the extra ", " combination will be avoided entirely).

Alternatively, you can reset the buffer manually:

std::ostringstream os;
os << '(';
std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>(os, ", "));
std::string t = os.str();
t.resize(t.size() - 2);
os.str() = t;
os << ')';

Or, perhaps a more uniform solution (if you are not opposed to not using copy):

std::ostringstream os;
os << '(';
if (v.size() > 1) // or (!v.empty())
    os << v.front();

std::for_each(v.begin() + 1, v.end(), [&](const std::string& s)
{
    os << ", " << s;
});
os << ")";
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top