I was looking for a solution to write to a file and the console at the same time. I found a nice solution here.
As I am working pre C++11 I had to make a small change to the code from Lightness Races in Orbit:
#include <iostream> #include <fstream> #include <string> struct OutputAndConsole : std::ofstream { OutputAndConsole(const std::string& fileName) : std::ofstream(fileName.c_str()) // constructor taking a string is C++11 , 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; };
It works nicely apart from a small thing takes puzzles me. If I use it like this:
int main(){ OutputAndConsole oac("testLog.dat"); double x = 5.0; oac << std::endl; static_cast<OutputAndConsole&>(oac << "foo \n" << x << "foo").operator<<(std::endl); oac << "foo" << std::endl; }
then all the std::endl
are ignored for the output on the console while they appear correctly in the file. My guess is that when I use std::endl
the ostream::operator<<
is called which will print to the file but not to the console. The line with the static_cast<OutputAndConsole&>
is my dilettantish attempt to call the correct operator, but still only the line break from \n
appears on the console.
Why for std::endl
the wrong operator is called?
How can I call the correct one?
PS: I know that I can use \n
without problems, but still I would like to know what is going on here and how to fix it.
With reference This is an output-only I/O manipulator. std::endl Inserts a newline character into the output sequence os and flushes it as if by calling os. put(os. widen('\n')) followed by os. flush() .
There is no std::cout in C. In a windowing system, the std::cout may not be implemented because there are windows and the OS doesn't know which one of your windows to output to. never ever give cout NULL. it will stop to work.
std::endl. Inserts a new-line character and flushes the stream. Its behavior is equivalent to calling os.
There is rarely a need for std::endl , and getting in the habit of using it will lead to mysteriously slow code. Just use '\n' unless you know you need to flush the buffer.
struct OutputAndConsole : std::ofstream { // ... }; template <typename T> OutputAndConsole& operator<<(OutputAndConsole& strm, const T& var);
As others have mentioned, std::endl
is a template function. A template function is not a value, it is just a name.
A template function can be converted to a value if you try to pass it to a function expecting function of a compatible signature. It is not converted to a value if passed to a template function taking T
or const T&
, because the name of a template function represents a whole host of possible values.
Because std::endl
is not a valid argument for your custom-written operator<<
, it looks elsewhere. It finds the std::ofstream
's operator<<
that takes an io manipulator function by explicit function pointer.
That one works, it can convert endl
to that function pointer type! So, gleefully, it calls it.
To fix this problem, add an operator<<
overload to OutputAndConsole
that takes io manipulator function pointers.
The easiest way to do that is to write a helper function:
template <class T> void output_to(OutputAndConsole& strm, const T& var) { std::cout << var; static_cast<std::ofstream&>(strm) << var; };
then two <<
overloads:
template<class T> OutputAndConsole& operator<<(OutputAndConsole& strm, const T& var) { output_to(strm, var); return strm; } OutputAndConsole& operator<<(OutputAndConsole& strm, std::ostream& (*var)(std::ostream&)) { output_to(strm, var); return strm; }
which causes the std::endl
template to find a matching <<
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With