How to determine weather ostream is a file or a console stream. In the following program I want to print "Hello file!" while writing to a file and "Hello console!" while writing to console. What condition should I specify at line 17?
#include <fstream>
#include<iostream>
#include <string>
using namespace std;
class A{
public:
A(string msg):_str(msg){}
string str()const {return _str;};
private:
string _str;
};
ostream & operator << (ostream & os, const A & a)
{
if (os is ofstream) //this is line 17
os << "Hello file! " << a.str() << endl;
else
os << "Hello console! " << a.str() << endl;
return os;
}
int main()
{
A a("message");
ofstream ofile("test.txt");
if (!ofile)
cerr << "Unable to open file";
else
ofile << a; // "Hello file"
cout << a << endl; // "Hello console"
}
Maybe not pretty, but
std::streambuf const * coutbuf = std::cout.rdbuf();
std::streambuf const * cerrbuf = std::cerr.rdbuf();
ostream & operator << (ostream & os, const A & a)
{
std::streambuf const * osbuf = os.rdbuf();
if ( osbuf == coutbuf || osbuf == cerrbuf )
os << "Hello console! " << a.str() << endl;
else
os << "Hello file! " << a.str() << endl;
return os;
}
We could use &os == &std::cout
, but the Standard output might be redirected to file, so I think it is better to use the streambuf object instead. (See this answer for better understanding as to how the redirection works, and why comparing streambuf solves the problem safely! )
You could (ab)use tellp()
, which returns -1
if the stream does not have a position:
bool isConsoleStream(ostream const& stream)
{
return stream.tellp() == -1;
}
Of course, there could be other streams that return -1
for this function, so use with caution.
There is no portable means. Under Unix, you can do:
if ( (&os == &std::cout && isatty( STDOUT ))
|| (&os == &std::cerr && isatty( STDERR ))
|| (&os == &std::clog && isatty( STDERR )) ) }
// is a terminal...
}
Under Windows, the isatty
becomes _isatty
, and I'm not sure
that the macros exist (but I suspect that they do).
Of course, this supposes that you don't do things to confuse it in your code. Something like:
std::ostream s( std::cout.rdbuf() );
for example, or:
std::cout.rdbuf( &someFileBuf );
Or even:
std::ofstream s( "/dev/tty" ); // (or "CONS" under Windows).
But it's about as close as you can get without the actual fd
from the filebuf
.
One is a ofstream
and the other is a ostream
. Just have two methods.
#include <iostream>
#include <string>
#include <fstream>
class A {
std::string s;
public:
A(const std::string& s) : s(s){}
std::string str() const {return s;}
};
ostream & operator << (std::ostream & os, const A & a)
{
return os << "console: " << a.str() << std::endl;
}
ofstream & operator << (std::ofstream & os, const A & a)
{
return os << "file: " << a.str() << std::endl;
}
int main()
{
A a("hello world");
std::cout << a << endl;
}
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