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(罗格特);

mLOut
std::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;

}