正确的方式来声明/定义类似自定义cout的对象

时间:2013-07-21 16:22:48

标签: c++ c++11 static global-variables extern

我创建了自己的std::cout - 类似对象,它将std::cout写入日志文件。

我目前在头文件中这样定义它,但我收到了未使用的变量警告。

标头文件<MyLib/Log.h>

static LOut { };
static LOut lo;

template<typename T> inline LOut& operator<<(LOut& mLOut, const T& mValue)
{
    std::string str{toStr(mValue)};
    std::cout << str;
    getLogStream() << str;
    return mLOut;
}

用法:

#include <MyLib/Log.h>
...
lo << "hello!" << std::endl;

lostatic吗? loextern吗?

Kudos解释了声明类似cout的对象的正确方法,并展示了主要标准库的实现方式。


编辑:按cout - 类似对象,我的意思是在包含相应标题后始终可用的全局变量。

4 个答案:

答案 0 :(得分:6)

std::cout简单地声明如下:

namespace std {
    extern ostream cout;
}

这是一个常规的全局变量;你可以自己做同样的事情。将变量的extern声明放在标题中;然后在源文件中定义相同的变量并将其链接到您的应用程序:

// mylog.h
extern MyLog mylog;

// mylog.cpp
MyLog mylog(someparams);

答案 1 :(得分:1)

首先,我不太清楚你的意思是cout对象? 也许是std::ostream

无论如何,通常的做法是使用过滤 流缓冲。只需编写一个转发到日志文件的streambuf, 除了通常的地方,并把它插入你的地方 想:

class LoggingOutputStreambuf : public std::streambuf
{
    std::streambuf* myDest;
    std::ofstreambuf myLogFile;
    std::ostream* myOwner;
protected:
    int overflow( int ch )
    {
        myLogFile.sputc( ch );  //  ignores errors...
        return myDest->sputc( ch );
    }
public:
    LoggingOutputStreambuf(
            std::streambuf* dest,
            std::string const& logfileName )
        : myDest( dest )
        , myLogFile( logfileName.c_str(), std::ios_base::out )
        , myOwner( nullptr )
    {
        if ( !myLogFile.is_open() ) {
            //  Some error handling...
        }
    }
    LoggingOutputStreambuf(
            std::ostream& dest,
            std::string const& logfileName )
        : LoggingOutputStreambuf( dest.rdbuf(), logfileName )
    {
        dest.rdbuf( this );
        myOwner = &dest;
    }
    ~LoggingOutputStreambuf()
    {
        if ( myOwner != nullptr ) {
            myOwner->rdbuf( myDest );
        }
    }
};

(这是C ++ 11,但要修改它应该不难 C ++ 03)

要使用,您可以使用以下内容:

LoggingOutputStreambuf logger( std::cout );
//   ...

std::cout的所有输出都将被记录,直到logger结束 范围。

在实践中,你可能会使用比a更复杂的东西 filebuf用于记录,因为您可能想要插入时间戳 在每一行的开头,或系统地在结束时冲洗 每一行。 (过滤streambufs可以处理这些问题 同样。)

答案 2 :(得分:1)

  

std :: cout-like对象,它将std :: cout和日志文件都写入

也许boost.iostreams就足够了?

#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;
}

答案 3 :(得分:0)

在我的一个projects中,我为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

中查找io.h