Obtain a std::ostream either from std::cout or std::ofstream(file)
std::streambuf * buf;
std::ofstream of;
if(!condition) {
of.open("file.txt");
buf = of.rdbuf();
} else {
buf = std::cout.rdbuf();
}
std::ostream out(buf);
That associates the underlying streambuf of either cout or the output file stream to out. After that you can write to "out" and it will end up in the right destination. If you just want that everything going to std::cout
goes into a file, you can aswell do
std::ofstream file("file.txt");
std::streambuf * old = std::cout.rdbuf(file.rdbuf());
// do here output to std::cout
std::cout.rdbuf(old); // restore
This second method has the drawback that it's not exception safe. You possibly want to write a class that does this using RAII:
struct opiped {
opiped(std::streambuf * buf, std::ostream & os)
:os(os), old_buf(os.rdbuf(buf)) { }
~opiped() { os.rdbuf(old_buf); }
std::ostream& os;
std::streambuf * old_buf;
};
int main() {
// or: std::filebuf of;
// of.open("file.txt", std::ios_base::out);
std::ofstream of("file.txt");
{
// or: opiped raii(&of, std::cout);
opiped raii(of.rdbuf(), std::cout);
std::cout << "going into file" << std::endl;
}
std::cout << "going on screen" << std::endl;
}
Now, whatever happens, std::cout is in clean state.
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.
How to use std::cout or std::ofstream as an input of a single function?
Don't use std::ofstream
in write
. Use std::ostream
.
void write(std::ostream& o)
{
o << "Some text..." << std::endl;
}
Also,
auto outputStream = std::ofstream(std::cout);
write();
is not right. Just use.
write(std::cout);
I'd change the first of the if
block too.
if (argc == 2){
std::ofstream outputStream(argv[1]);
write(outputStream);
}
else{
write(std::cout);
}
how to temporarily use std::cout in place of std::ofstream
Think of std::cout
of what it actually is: an object. It is just that:
The global objects
std::cout
andstd::wcout
control output to […]
So when you say that you want to temporarily use std::cout
in place of std::ofstream
you're mixing apples (object std::cout
) with oranges (class std::ofstream
).
What you want to do, instead, is to use std::cout
instead of an object of class std::ofstream
.
But std::cout
is not of class std::ofstream
, so error
can't hold it; it is of class std::ostream
, which is a superclass of the former.
Therefore, as suggested in a comment, you can make error
/event
references to an object of that class, std::ofstream
std::ostream&
, and initialize them with std::cout
or with std::ofstream{"filename.txt"}
via an appropriate constructor of the logging_class
.
Good practice to write binary stream to either a file or stdout
My version would something more akin to this:
#include <iostream>
#include <fstream>
void function2(bool bWriteConsole)
{
std::ofstream outfile;
if (!bWriteConsole)
outfile.open("./hello.bin", std::ofstream::binary | std::ofstream::out);
double dValue = 1.2345;
// writing out
std::ostream& out = bWriteConsole ? std::cout : outfile;
out.write(reinterpret_cast<char*>(&dValue), sizeof dValue);
out.flush();
}
Writing code is 2 lines, 3 if you really want to flush. outfile.close()
would flush as well, so there is no harm in flushing unconditionally versus your approach. File will get closed when outfile
goes out of scope so it doesn't have to be written unless you really want to manually close the file before some further processing. Here it's superfluous (RAII goodness comes into play here).
Aaand maybe refactor writing:
template<typename T>
void dump(T val, std::ostream& out ) {
out.write(reinterpret_cast<char*>(&val), sizeof val);
out.flush();
}
void function2(bool bWriteConsole)
{
std::ofstream outfile;
if (!bWriteConsole)
outfile.open("./hello.bin", std::ofstream::binary | std::ofstream::out);
double dValue = 1.2345;
dump(dValue, bWriteConsole ? std::cout : outfile);
// writing out
}
Check if ostream object is cout or ofstream, c++
It's possible by checking the stream's 'identity': if ( &out == &cout ) ...
.
However, I'm in doubt on the usefullness of this test. If your function can handle any output stream, why bother about what stream it is using?
Proper way to create ostream to file or cout
You create tmp
with std::ostream tmp(buf);
and store the address of it in out
with this->out = &tmp;
. However, tmp
will go out of scope at the end of the constructor and the pointer will no longer be pointing at a valid object.
What you should do instead is make out
not a std::ostream*
but simply a std::ostream
:
std::ostream out;
Then in your constructor, once you've got the buf
ready, you can give it to out
by doing out.rdbuf(buf);
.
Response to edit:
The std::ostream
doesn't have a default constructor - it has to take a buffer pointer. My mistake. However, the fix is simple. Use your constructor's member initialization list to pass a null pointer (nullptr
in C++11, 0
or NULL
in C++03):
Log::Log(const char *file)
: out(nullptr)
{
// ...
}
How to switch between std::ofstream and std::cerr
You will have to dynamically-allocate your streams:
std::unique_ptr<std::ostream> get_stream() {
bool flag = time(0) % 2;
return ( flag
? std::make_unique<std::ostream>(std::cerr.rdbuf())
: std::make_unique<std::ofstream>("somefile.txt")
);
}
int main() {
auto logger {get_stream()};
*logger << "Just testing, everything is fine."
<< std::endl;
}
Copy the contents of std::ofstream into an std::string
No. "the contents of this std::ofstream
" is nonsensical. The file has contents, the stream is a handle that represents writing to the file.
Either flush ofs
and read the file, or use std::ostream &
in place of std::ofstream &
.
Related Topics
How to Set Visual Studio Filters for Nested Sub Directory Using Cmake
How to Write Portable Code in C++
C++ Template Functions Overload Resolution
Can C++ Have Code in the Global Scope
Rotate an Image in C++ Without Using Opencv Functions
C++ Function Callbacks: Cannot Convert from a Member Function to a Function Signature
C++: How to Implement Polymorphic Object Creator to Populate a Table
C++ - Why Static Member Function Can't Be Created with 'Const' Qualifier
Is a '=Default' Move Constructor Equivalent to a Member-Wise Move Constructor
How to Force Cache Coherency on a Multicore X86 Cpu
How to Define Several Include Path in Makefile
Why Can't I Create a Vector of Lambdas (Of the Same Type) in C++11
Convert Float to Std::String in C++
Const and Non-Const Operator Overloading
Lcov/Gcov Branch Coverage with C++ Producing Branches All Over the Place