I would like to write a function that returns an ostream that either writes to a file or stderr.
My first attempt:
#include <fstream>
#include <iostream>
std::ostream get_stream() {
bool flag = (time(nullptr) % 2); // stand-in
if (flag)
return std::cerr;
else
return std::ofstream{"somefile.txt"};
}
int main() {
auto logger {get_stream()};
logger << "Just testing, everything is fine."
<< std::endl;
}
This fails with a (long) compiler error - I suspect because std::cerr
does not have a copy constructor. Another variant (returning a reference) does not work because the ofstream
is a local variable. I could allocate the ofstream
on the heap, but then the caller doesn't know if the pointer needs to be freed (it doesn't when we return a reference to std:cerr
).
So, I wrote version 2:
#include <fstream>
#include <iostream>
struct Logger {
std::ofstream ostream;
bool to_stderr {true};
template<typename A>
Logger& operator<<(A rhs) {
if (to_stderr)
std::cerr << rhs;
else
ostream << rhs;
return this;
}
};
int main() {
Logger logger;
logger << "Just testing, everything is fine."
<< std::endl;
}
This also fails with a long compile error that starts with:
$ g++ -Wall -o v2 v2.cpp
v2.cpp: In function ‘int main()’:
v2.cpp:30:12: error: no match for ‘operator<<’ (operand types are ‘Logger’ and ‘<unresolved overloaded function type>’)
logger << "Just testing, everything is fine."
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<< std::endl;
^~~~~~
v2.cpp:9:13: note: candidate: template<class A> Logger& Logger::operator<<(A)
Logger& operator<<(A rhs) {
^~~~~~~~
v2.cpp:9:13: note: template argument deduction/substitution failed:
v2.cpp:30:20: note: couldn't deduce template parameter ‘A’
<< std::endl;
^~~~
[...]
Why isn't the second version working, and what is the right way to implement something like this?
(Using << operator to write to both a file and cout is a related question, but as far as I can tell the only difference in the solution given there is that operator<<
is defined outside the class, and if I make the same change to my code, I'm still getting the same error)