2

I am trying to use an ostream object to write to either to a filestream of stringstream based user input (similar to fmemopen in Linux).

I realized that ostream doesnt take stringstream or fstream objects but instead takes stringbug or filebuf.

I tried the following code:

    char content[] = "This is a test";
    if (isFile)
    {
        filebuf fp;
        fp.open(filename, ios::out);
        ostream os(&fp);
        os << content;
        fp.close();
    }
    else
    {
        stringbuf str;
        ostream os(&str);
        os << content;
    }

This works fine, in the if else condition but I would like to use the ostream os, as os << content, outside the if else condition. The issue is however I am unable to globally define ostream os since there is no such constructor for ostream.

Is there a way to get around this?

Trancey
  • 699
  • 1
  • 8
  • 18
  • 3
    Separate writing the data from setting up the output mechanism. Write a function that inserts the data into a stream. That function should take an `std::ostream` by reference and write the data there. When you call the function, pass an `std::ofstream` or an `std::ostringstream`, as appropriate. – Pete Becker Apr 12 '19 at 01:02
  • That is something I can work with. Is there a way to default initialize the `insertdata(ostream& os)` to say `insertdata(ostream& os = ofstream("temp.txt",ios::out)`? This gives me an error. It works if I make `const ostream& os` but then the os.write throws a compilation error. – Trancey Apr 12 '19 at 04:43
  • @Trancey a non-const reference can't bind to a temporary object. Besides, this is not a scenario where a default value makes sense to use. The caller needs to specify what type of stream the function should write to. – Remy Lebeau Apr 12 '19 at 09:43

1 Answers1

3

This can be handled a couple of different ways.

Using a helper function:

void write(ostream &os, const char *content)
{
    os << content
}

...

char content[] = "This is a test";
if (isFile)
{
    ofstream ofs(filename);
    write(ofs, content);
}
else
{
    ostringstream oss;
    write(oss, content);
    string s = oss.str();
    // use s as needed...
}

Alternatively, using a lambda:

char content[] = "This is a test";
auto write = [](ostream &os, const char *content){ os << content; }

if (isFile)
{
    ofstream ofs(filename);
    write(ofs, content);
}
else
{
    ostringstream oss;
    write(oss, content);
    string s = oss.str();
    // use s as needed...
}

Using a pointer instead:

char content[] = "This is a test";
std::unique_ptr<ostream> os;

if (isFile)
    os = std::make_unique<ofstream>(filename);
else
    os = std::make_unique<ostringstream>();

*os << content;

if (!isFile)
{
    string s = static_cast<ostringstream*>(os.get())->str(); // or: static_cast<ostringstream&>(*os).str()
    // use s as needed...
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • This helps! `*os << content` for ostringstream, can this be written to a ostringstream object? It seems like I can retrieve it from streambuf pointer rdbuf but I cannot put that into a standard string or stringstream. – Trancey Apr 12 '19 at 20:05
  • My mistake, `*oss << content` should have been `*os << content`. And yes, this can write to an `ostringstream`, since it is an `ostream` descendant. To get the `string` afterwards, you can cast the `ostream` back to `ostringstream` so you can call its `str()` method. I have updated my answer to show that – Remy Lebeau Apr 12 '19 at 20:31