如何确定天气ostream是文件或控制台流。在下面的程序中,我想要打印" Hello file!"写入文件和" Hello控制台!"在写入控制台时。我应该在第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"
}
答案 0 :(得分:4)
也许不漂亮,但
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;
}
我们可以使用&os == &std::cout
,但标准输出可能会重定向到文件,所以我认为最好使用streambuf对象。 (请参阅this answer以更好地了解重定向的工作原理,以及为什么比较streambuf安全地解决问题!)
答案 1 :(得分:3)
您可以(ab)使用tellp()
,如果流没有位置,则返回-1
:
bool isConsoleStream(ostream const& stream)
{
return stream.tellp() == -1;
}
当然,可能有其他流为此函数返回-1
,因此请谨慎使用。
答案 2 :(得分:2)
一个是ofstream
,另一个是ostream
。只有两种方法。
#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;
}
答案 3 :(得分:2)
没有便携式手段。在Unix下,你可以这样做:
if ( (&os == &std::cout && isatty( STDOUT ))
|| (&os == &std::cerr && isatty( STDERR ))
|| (&os == &std::clog && isatty( STDERR )) ) }
// is a terminal...
}
在Windows下,isatty
变为_isatty
,我不确定
宏存在(但我怀疑它们确实存在)。
当然,这假设您不会做任何事情来混淆它 在你的代码中。类似的东西:
std::ostream s( std::cout.rdbuf() );
例如,或:
std::cout.rdbuf( &someFileBuf );
甚至:
std::ofstream s( "/dev/tty" ); // (or "CONS" under Windows).
但是如果没有实际的fd
,它就会尽可能接近
来自filebuf
。
答案 4 :(得分:0)
这适用于Visual Studio 2012
if (typeid(os) == typeid(ofstream)) //this is line 17
但ostream
可能不属于游戏或控制台,因此您必须小心。
答案 5 :(得分:0)
用于检查C ++字符流是否已连接到终端/控制台/ tty的功能。
理想情况下,我们将使用位于C ++ stdio流(cin,cout,cerr或clog)的流缓冲区下面的文件描述符。 但是,没有办法检索底层文件描述符。 因此,我们可以利用以下事实:在程序启动时,stdio流缓冲区将连接到程序的标准输入和输出。
此功能仅在以下情况下起作用:
启动的C ++ stdio流的流缓冲区不得更改。 因为启动C ++ stdio流的流缓冲区的地址用作标识符。 例如,先删除它们,然后分配一个新的流缓冲区,该缓冲区的地址与启动C ++ stdio流的这些流缓冲区之一的地址相同。
程序启动后不得更改程序的stdio。 因为stdio流缓冲区的TTY状态是在程序启动时存储的。 例如,如果在启动std。 out连接到终端,然后通过程序外部的东西重定向到管道或文件。 [代替在启动时存储TTY状态,您可以在运行时检索它们,但随后必须确保程序(及其使用的所有库)不会更改stdio文件描述符(0、1和2)。 。得知stdio流缓冲区最有可能使用其他(重复的)文件描述符。]
代码:
#include <iostream>
extern "C" {
#ifdef _WIN32
# include <io.h> // for: _isatty()
#else
# include <unistd.h> // for: isatty()
#endif
}
// Stdio file descriptors.
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
# define STDOUT_FILENO 1
# define STDERR_FILENO 2
#endif
// Store start-up addresses of C++ stdio stream buffers as identifiers.
// These addresses differ per process and must be statically linked in.
// Assume that the stream buffers at these stored addresses
// are always connected to their underlaying stdio files.
static const streambuf* const StdioBufs[] = {
std::cin.rdbuf(), std::cout.rdbuf(), std::cerr.rdbuf(), std::clog.rdbuf()
};
static const wstreambuf* const StdioWBufs[sizeof(StdioBufs)/sizeof(StdioBufs[0])] = {
std::wcin.rdbuf(), std::wcout.rdbuf(), std::wcerr.rdbuf(), std::wclog.rdbuf()
};
// Store start-up terminal/TTY statuses of C++ stdio stream buffers.
// These statuses differ per process and must be statically linked in.
// Assume that the statuses don't change during the process life-time.
static const bool StdioTtys[sizeof(StdioBufs)/sizeof(StdioBufs[0])] = {
#ifdef _WIN32
_isatty(STDIN_FILENO), _isatty(STDOUT_FILENO), _isatty(STDERR_FILENO), _isatty(STDERR_FILENO)
#else
isatty(STDIN_FILENO), isatty(STDOUT_FILENO), isatty(STDERR_FILENO), isatty(STDERR_FILENO)
#endif
};
// Is a Terminal/Console/TTY connected to the C++ stream?
// Use on C++ stdio chararacter streams: cin, cout, cerr and clog.
bool isTTY(const ios& strm)
{
for(unsigned int i = 0; i < sizeof(StdioBufs)/sizeof(StdioBufs[0]); ++i) {
if(strm.rdbuf() == StdioBufs[i])
return StdioTtys[i];
}
return false;
}
// Is a Terminal/Console/TTY connected to the C++ stream?
// Use on C++ stdio wide-chararacter streams: wcin, wcout, wcerr and wclog.
bool isTTY(const wios& strm)
{
for(unsigned int i = 0; i < sizeof(StdioWBufs)/sizeof(StdioWBufs[0]); ++i) {
if(strm.rdbuf() == StdioWBufs[i])
return StdioTtys[i];
}
return false;
}
注意:我只在Linux上进行过测试。