Using << Operator to Write to Both a File and Cout

Using operator to write to both a file and cout

Create a helper class and overload operators that takes care of streaming to two streams. Use the helper class instead of trying to override the standard library implementations of the overloaded operator<< functions.

This should work:

#include <iostream>
#include <fstream>

struct MyStreamingHelper
{
MyStreamingHelper(std::ostream& out1,
std::ostream& out2) : out1_(out1), out2_(out2) {}
std::ostream& out1_;
std::ostream& out2_;
};

template <typename T>
MyStreamingHelper& operator<<(MyStreamingHelper& h, T const& t)
{
h.out1_ << t;
h.out2_ << t;
return h;
}

MyStreamingHelper& operator<<(MyStreamingHelper& h, std::ostream&(*f)(std::ostream&))
{
h.out1_ << f;
h.out2_ << f;
return h;
}

int main()
{
std::ofstream fl;
fl.open("test.txt");
MyStreamingHelper h(fl, std::cout);
h << "!!!Hello World!!!" << std::endl;
return 0;
}

trying to write std:out and file at the same time

The problem

ofstream::operator << (var);

It's your use of ofstream::operator<< as a qualified function call. You're mandating that the function lookup locate a member function of ofstream; the best match that's a member is the one for void*, whereas the specialisation for char* that prints the actual string contents is a free function (i.e. not a member function).

You'll find the same problem if you do this with cout, too:

std::cout.operator<<(var);

The solution

This might do it:

static_cast<ofstream&>(*this) << var;

because you're still using normal operator syntax (with all the overload resolution that this entails), but doing so with an ofstream as the LHS operand.

I haven't actually tested it, though.

Conclusion

As an aside, your operator<< ought to be a free function too, in order to fit in with this convention.

So:

struct OutputAndConsole : std::ofstream
{
OutputAndConsole(const std::string& fileName)
: std::ofstream(fileName)
, fileName(fileName)
{};

const std::string fileName;
};

template <typename T>
OutputAndConsole& operator<<(OutputAndConsole& strm, const T& var)
{
std::cout << var;
static_cast<std::ofstream&>(strm) << var;
return strm;
};

I also took the liberty of making some minor syntax adjustments.

Why and how to overload operator for printing

For question 1, your understanding is correct, but the real improvement comes from question 2's suggestion of writing:

template <typename T>
friend std::ostream& operator<<(std::ostream&, Mystack<T> const& );

That will let anybody stream objects of your type in the same way they would stream anything else:

std::cout << "Hi, my stack is " << stack << ", it has size " << stack.size();

to any stream they want:

some_file << "Result of computation is: " << stack;
std::cerr << "Error, invalid stack: " << stack << ", expected: " << some_other_thing;

How to overload and to use them for file writing and reading of a class

The operators operator<< and operator>> are overloaded using a return-by-reference because they take in objects and output the cout (or cin) object containing those objects. Try:

istream& operator>>(istream& in, Record& g) {
//do stuff here
}

They need to be returned-by-reference because they have to be able to take in other stream objects that derive from it, such as ifstream. Now your program can read files that contain Record objects.

The main reason for the error is because the constructor for basic_ostream (which iostream is a child of, which cin is a type of) is protected (which is also what your error says). But did you see that because it's protected, its children (cin, cout) can be instantiated?

Unfortunately iostream doesn't have a operator>> or operator<< function, so we can't declare iostream& operator>>(iostream& iO, myType mT). So we have to use ostream types.

Overloading to output into a file

It is usually a bad idea to restrict a function to std::ofstream when it may as well work with any kind of std::ostream. It also looks highly suspicious when you pass a non-const reference to a print function. This means that you officially allow printing to have side effects which modify the printed object!

For those reasons, you should change this:

std::ofstream & operator <<(std::ofstream & output, myClass & s);

To this:

std::ostream & operator <<(std::ostream & output, myClass const& s);

You don't need to create a stream instance in the implementation of the operator, either. You receive a reference to one as the first argument. So just do this (and while we're at it, avoid endl unless you know exactly what you are doing):

std::ostream & operator <<(std::ostream & output, myClass const& s);
{
output << "Test\n";
// output << s.some_member << "\n";
return output;
}

You can now just pass an std::ofstream object to that function and will write into the file. You just need to create the object, passing the filename to its constructor:

myClass s;
std::ofstream os("output.txt");
os << s;

ostream: class that outputs either on cout or on a file

I would try to split here the stream creation with the stream usage. std::ostream is already polymorphic, so as long as you pass a reference or pointer to the function that uses the stream, all good.

For the creation, I would go for creating the stream in the heap, as the post you linked to suggests. However, doing explicit memory management (raw new/delete) is dangerous, so I would use a smart pointer, like std::unique_ptr:

#include <fstream>
#include <memory>

struct ConditionalDeleter
{
bool must_delete;
void operator()(std::ostream* os) const { if (must_delete) delete os; }
};

using OstreamPtr = std::unique_ptr<std::ostream, ConditionalDeleter>;

OstreamPtr create_stream(bool to_file)
{
if (to_file)
return OstreamPtr { new std::ofstream {"myfile.txt"}, ConditionalDeleter {true} };
else
return OstreamPtr { &std::cout, ConditionalDeleter {false} };
}

void use_stream(std::ostream& os)
{
os << "Hello world!" << std::endl;
}

int main()
{
auto streamptr = create_stream(false);
use_stream(*streamptr);
}

I've used a custom deleter with std::unique_ptr. The reason for that is: if we are using the file, I want the stream to be deleted; but std::cout is a global object, which we must not delete. The agreement here is that when your OstreamPtr gets destroyed, ConditionalDeleter::operator() will get called. *streamptr returns you a reference to your std::ostream, which you can use as you want.

Please note you need C++11 support to use this solution.

C++ cout like function, which writes data to file (logging)

You could have a templated operator<<:

#include <sstream>
struct Log
{
void write(std::string const& s);

template<class T>
Log& operator<<(T const& msg)
{
std::stringstream ss;
ss << msg;
write(ss.str());
return *this;
}
};

This would be a possible usage:

int main(int argc, char **argv)
{
Log log;
log << 8;
log << "Hello, " << "World!";
std::string msg("plop");
log << msg;
}

Demo

std::cout don't work with overloaded '' operator for struct

Your operator<< is declared as

std::ofstream& operator<<(std::ofstream &os, const LevelStats &stats);

Notice that you're passing and returning a reference to std::ofstream.
Writing to file will work because you will pass a std::ofstream&, but std::cout is not a std::ofstream& and can not bind to std::ofstream&.

If you want to be able to output your struct using std::cout while still beeing able to use std::ofstream, change your operator<< to

std::ostream& operator<<(std::ostream &os, const LevelStats &stats);

Both std::ofstream and std::ostream can bind to std::ostream &os, allowing you to write your struct to both files and std::cout.



Related Topics



Leave a reply



Submit