Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does `<< std::endl` not call the operator I want it to call?

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.

like image 978
463035818_is_not_a_number Avatar asked Jun 28 '16 11:06

463035818_is_not_a_number


People also ask

What is << std :: endl?

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() .

Why is std :: cout not working?

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.

How does STD Endl work?

std::endl. Inserts a new-line character and flushes the stream. Its behavior is equivalent to calling os.

Is std :: endl necessary?

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.


1 Answers

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 <<.

like image 137
Yakk - Adam Nevraumont Avatar answered Oct 07 '22 00:10

Yakk - Adam Nevraumont