C++ 声明/定义自定义类cout对象的正确方法
我创建了自己的C++ 声明/定义自定义类cout对象的正确方法,c++,c++11,static,global-variables,extern,C++,C++11,Static,Global Variables,Extern,我创建了自己的std::cout——类似于对象的对象,它既可以写入std::cout,也可以写入日志文件 我现在在头文件中这样定义它,但是我得到了未使用的变量警告 头文件 static LOut{}; 静态LOut-lo; 模板内联LOut&operator首先,我不太确定你所说的“像cout一样的对象”是什么意思? 可能是一个std::ostream 无论如何,通常的方法是使用过滤 streambuf。只需编写一个streambuf,将其转发到日志文件, 除了通常的位置,并将其插入任何您需要的
std::cout
——类似于对象的对象,它既可以写入std::cout
,也可以写入日志文件
我现在在头文件中这样定义它,但是我得到了未使用的变量警告
头文件
static LOut{};
静态LOut-lo;
模板内联LOut&operator首先,我不太确定你所说的“像cout
一样的对象”是什么意思?
可能是一个std::ostream
无论如何,通常的方法是使用过滤
streambuf。只需编写一个streambuf,将其转发到日志文件,
除了通常的位置,并将其插入任何您需要的位置
想要:
(这是C++11,但要修改它并不难
C++03。)
要使用,您可以使用以下内容:
LoggingOutputStreambuf logger( std::cout );
// ...
所有到std::cout
的输出都将被记录,直到logger
熄灭
范围有限
实际上,您可能会使用比
filebuf
用于日志记录,因为您可能需要插入时间戳
在每条管线的起点,或在管线的末端进行系统冲洗
每行。(过滤流BUFS可以解决这些问题
同样。)在我的一篇文章中,我为std::cout
编写了包装器
它看起来像这样:
struct out_t {
template<typename T>
out_t&
operator << (T&& x) {
std::cout << x;
// log << x;
return *this;
};
};
out_t out;
out << 1;
struct out\t{
模板
外面&
操作人员
类似于std::cout的对象,它同时写入std::cout和日志文件
也许就足够了
#include <iostream>
#include <fstream>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/tee.hpp>
namespace io = boost::iostreams;
int main()
{
typedef io::tee_device<std::ostream, std::ofstream> teedev;
typedef io::stream<teedev> LOut;
std::ofstream outfile("test.txt");
teedev logtee(std::cout, outfile);
LOut mLOut(logtee);
mLOut << "hello!" << std::endl;
}
#包括
#包括
#包括
#包括
名称空间io=boost::iostreams;
int main()
{
类型定义io::tee_设备teedev;
类型定义io::流LOut;
标准:流出管(“test.txt”);
teedev logtee(标准:cout,输出文件);
LOut mLOut(罗格特);
mLOutstd::cout
简单声明如下:
namespace std {
extern ostream cout;
}
它是一个常规全局变量;您可以自己做同样的事情。将变量的extern
声明放在标题中;然后在源文件中定义相同的变量,并将其链接到应用程序:
// mylog.h
extern MyLog mylog;
// mylog.cpp
MyLog mylog(someparams);
简单地将输入值直接发送到cout对我来说不起作用,因为我想向日志输出中添加标题和信息
此外,我还有一个静态调试类,可以在其中包装日志流
<>这是我设法做到的,我希望它有用。我不知怎么地对C++有了一个新的告别,所以请告诉我有什么不对的地方:
#包括
#包括
#包括
枚举类调试级别{
信息,
警告
错误
};
类调试{
公众:
/*其他调试类方法/属性
...
*/
//输出流对象
静态结构扩展{
std::奥斯汀溪流;
DebugLevel=DebugLevel::INFO;
公众:
//在这里,您可以向对象、每行日志添加参数
扩展流和运算符()(调试级别l){
级别=l;
归还*这个;
}
//这个重载通过std::cout
接收要附加的单个值,通常只是某种类型的std::ostream
,带有一些特殊的逻辑,以确保它足够早地初始化,并且永远不会被破坏;我知道至少有一个编译器使用特殊的扩展来实现这一点。但您通常不需要它;如果更糟的情况发生了,则不需要它更糟糕的是,您可以使用单例并编写log(),谢谢,但我希望有一个始终可用的全局变量,这就是为什么我谈到了cout
-like对象,所以您关心的是生命周期。这一点并不清楚。在这种情况下,显而易见的解决方案是std::ostream&logStream(){static std::ostream*theOneAndOnly=new MyStreamType;return*theOneAndOnly;}
语法有一点变化:您必须编写logStream()我不想引入任何boost依赖项,我想要一个全局变量,比如cout
,这更接近我想要的-但是我想要一个out的全局实例,可以在没有操作符()的情况下使用,就像cout
那样。没有任何东西可以让您声明全局out
对象。我编辑了代码来演示如何执行该操作。@LeonidVolnitsky如果我没有使用C++11,是否可以在显示的代码段中将&
替换为&
?谢谢。我曾尝试声明它外部,但忘记了在源文件中定义变量。
#include <iostream>
#include <fstream>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/tee.hpp>
namespace io = boost::iostreams;
int main()
{
typedef io::tee_device<std::ostream, std::ofstream> teedev;
typedef io::stream<teedev> LOut;
std::ofstream outfile("test.txt");
teedev logtee(std::cout, outfile);
LOut mLOut(logtee);
mLOut << "hello!" << std::endl;
}
namespace std {
extern ostream cout;
}
// mylog.h
extern MyLog mylog;
// mylog.cpp
MyLog mylog(someparams);
#include <iostream>
#include <sstream>
#include <ostream>
enum class DebugLevel {
INFO,
WARNING,
ERROR
};
class Debug {
public:
/* other Debug class methods/properties
...
*/
// out stream object
static struct OutStream {
std::ostringstream stream;
DebugLevel level = DebugLevel::INFO;
public:
// here you can add parameters to the object, every line log
OutStream& operator()(DebugLevel l) {
level = l;
return *this;
}
// this overload receive the single values to append via <<
template<typename T>
OutStream& operator<<(T&& value) {
stream << value;
return *this;
}
// this overload intercept std::endl, to flush the stream and send all to std::cout
OutStream& operator<<(std::ostream& (*os)(std::ostream&)) {
// here you can build the real console log line, add colors and infos, or even write out to a log file
std::cout << __TIME__ << " [" << (int)level << "] " << stream.str() << os;
stream.str(""); // reset the string stream
level = DebugLevel::INFO; // reset the level to info
return *this;
}
} Log;
};
Debug::OutStream Debug::Log; // need to be instantiaded only because I use a static Debug class
int main() {
Debug::Log(DebugLevel::ERROR) << "Hello Log! " << 2 << " " << __FUNCTION__ << std::endl;
Debug::Log << "Hello Log! " << 0xFA << std::endl; // NB: this way the debugLevel is default
return 0;
}