简单的 wostream 日志记录类(带有自定义流操纵器)

发布于 2024-10-02 05:44:25 字数 2716 浏览 2 评论 0原文

我已经阅读了大量的问题、文章和文档,但我还没有找到解决我的问题的方法。

我想创建一个简单的类用于调试。最终结果将允许我做这样的事情:

logger << error << L"This is a problem!" << endl;
logger << warning << L"This might be a problem!" << endl;
logger << info << L"This isn't a problem but I thought you should know about it" << endl;

有了这样的想法,在记录器类中,我可以切换这些东西是否进入控制台/调试文件。

logger.setLevel(ERROR);

我已经有了一个骨架,但我无法让操作员重载以使操纵器工作。

这是 Logger.h:

class LoggerBuffer : public wfilebuf {
// Functions
    public:
        LoggerBuffer() { wfilebuf::open("NUL", ios::out); currentState = 1;}
        ~LoggerBuffer() {wcout << "DELETED!" << endl;}
        void open(const char fname[]);
        void close() {wfilebuf::close();} 
        virtual int sync();
        void setState(int newState);
// Variables
    private:
         int currentState;
};

class LoggerStream : public wostream {
// Functions
    public:
         LoggerStream() : wostream(new LoggerBuffer()), wios(0) {}
         ~LoggerStream() { delete rdbuf(); }
         void open(const char fname[] = 0) { 
    wcout << "Stream Opening " << fname << endl;((LoggerBuffer*)rdbuf())->open(fname); }
         void close() { ((LoggerBuffer*)rdbuf())->close(); }
         void setState(int newState);
};

和 Logger.cpp:

void LoggerBuffer::open(const char fname[]) {
    wcout << "Buffer Opening " << fname << endl;
    close();
    wfilebuf* temp = wfilebuf::open(fname, ios::out);
    wcout << "Temp: " << temp << endl;
}
int LoggerBuffer::sync() {
    wcout << "Current State: " << currentState << ", Data: " << pbase();
    return wfilebuf::sync();
}
void LoggerBuffer::setState(int newState) {
    wcout << "New buffer state = " << newState << endl;
    currentState = newState;
}

void LoggerStream::setState(int newState) {
    wcout << "New stream state = " << newState << endl;
    ((LoggerBuffer*)rdbuf())->setState(newState);
}

和 main.cpp:

struct doSetState {
    int _l;    
    doSetState ( int l ): _l ( l ) {}

    friend LoggerStream& operator<< (LoggerStream& os, doSetState fb ) {
        os.setState(3);
        return (os);
    }
};

...
LoggerStream test;
test.open("debug.txt");
test << "Setting state!" << doSetState(1) << endl;
...

这种混乱在 VS2005 中产生以下错误:

“错误 C2679:二进制 '<<' : 不 发现运算符需要一个 类型的右侧操作数 'doSetState'(或者没有 可接受的转换)”

非常感谢任何帮助。

谢谢!

I've been reading tons of questions, articles, and documentation, but I've not found a solution to my problem.

I'd like to create a simple class for use in debugging. The end result of which would allow me to do something like this:

logger << error << L"This is a problem!" << endl;
logger << warning << L"This might be a problem!" << endl;
logger << info << L"This isn't a problem but I thought you should know about it" << endl;

With the idea that within the logger class I can toggle whether or not these things make it to the console/debug file.

logger.setLevel(ERROR);

I've got a skeleton together but I can't get the operator overloading for the manipulators to work.

Here's Logger.h:

class LoggerBuffer : public wfilebuf {
// Functions
    public:
        LoggerBuffer() { wfilebuf::open("NUL", ios::out); currentState = 1;}
        ~LoggerBuffer() {wcout << "DELETED!" << endl;}
        void open(const char fname[]);
        void close() {wfilebuf::close();} 
        virtual int sync();
        void setState(int newState);
// Variables
    private:
         int currentState;
};

class LoggerStream : public wostream {
// Functions
    public:
         LoggerStream() : wostream(new LoggerBuffer()), wios(0) {}
         ~LoggerStream() { delete rdbuf(); }
         void open(const char fname[] = 0) { 
    wcout << "Stream Opening " << fname << endl;((LoggerBuffer*)rdbuf())->open(fname); }
         void close() { ((LoggerBuffer*)rdbuf())->close(); }
         void setState(int newState);
};

And Logger.cpp:

void LoggerBuffer::open(const char fname[]) {
    wcout << "Buffer Opening " << fname << endl;
    close();
    wfilebuf* temp = wfilebuf::open(fname, ios::out);
    wcout << "Temp: " << temp << endl;
}
int LoggerBuffer::sync() {
    wcout << "Current State: " << currentState << ", Data: " << pbase();
    return wfilebuf::sync();
}
void LoggerBuffer::setState(int newState) {
    wcout << "New buffer state = " << newState << endl;
    currentState = newState;
}

void LoggerStream::setState(int newState) {
    wcout << "New stream state = " << newState << endl;
    ((LoggerBuffer*)rdbuf())->setState(newState);
}

And main.cpp:

struct doSetState {
    int _l;    
    doSetState ( int l ): _l ( l ) {}

    friend LoggerStream& operator<< (LoggerStream& os, doSetState fb ) {
        os.setState(3);
        return (os);
    }
};

...
LoggerStream test;
test.open("debug.txt");
test << "Setting state!" << doSetState(1) << endl;
...

This mess produces the following error in VS2005:

"error C2679: binary '<<' : no
operator found which takes a
right-hand operand of type
'doSetState' (or there is no
acceptable conversion)"

Any help is GREATLY appreciated.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

留蓝 2024-10-09 05:44:25

您的 ostream 操作员没有正确的签名。应该是:

friend LoggerStream&运算符<< (LoggerStream&os, const doSetState&fb)

(必须使用引用,因为单遍编译器在类定义中途不知道 doSetState 的大小。)

Your ostream operator does not have the correct signature. It should be:

friend LoggerStream& operator<< (LoggerStream& os, const doSetState& fb )

(It is necessary to use a reference, because a single-pass compiler does not know the size of doSetState when it is midway through the class definition.)

梦一生花开无言 2024-10-09 05:44:25

问题是,当您这样做时:

test << "Setting state!"

它返回一个基本的 wostream 对象。因此链接它不起作用,因为没有重载:

wostream& operator<< (wostream& os, const doSetState& fb )

但是您可以在单独的行上执行此操作,如下所示:

test << "Setting state!";
test << doSetState(1) << endl;

The problem is that when you do this:

test << "Setting state!"

It returns a basic wostream object. So chaining it doesn't work, since there is no overload for:

wostream& operator<< (wostream& os, const doSetState& fb )

You can however do it on separate lines, like this:

test << "Setting state!";
test << doSetState(1) << endl;
友谊不毕业 2024-10-09 05:44:25

我会采取稍微不同的方法。

我的记录器类中有一个 std::wfostream 成员,而不是从 std::wostream 继承。然后,您可以拥有一个通用模板化operator<<,它有选择地转发到嵌入流。

例如:

class Logger;

template<class T> Logger& operator<<(Logger&, const T&);

enum LogLevel
{
    debug,
    info,
    warning,
    error
};

class Logger
{
public:
    void open(const char* file) { stream.open(file); }
    void close() { stream.close(); }
    void passLevel(Loglevel level) { pass = level; }
    void logLevel(LogLevel level) { current = level; }
private:
    bool passThrough() { return current >= pass; }

    std::wofstream stream;
    LogLevel pass;
    LogLevel current;

    friend template<class T> Logger& operator<<(Logger&, const T&);
};

template<class T> 
Logger& operator<<(Logger& log, const T& rhs)
{
    if (log.passthrough())
    {
        log.stream << rhs; 
    }
    return log;
}

Logger& operator<<(Logger&, LogLevel level)
{
    log.logLevel(level);
    return log;
}

struct setLogLevel {
    setLogLevel(LogLevel l) : level(l) { }
    LogLevel level;
};

Logger& operator<<(Logger&, const setLogLevel setter)
{
    log.passLevel(setter.level);
    return log;
}

I would go for a slightly different approach.

Instead of inheriting from std::wostream, I would have a std::wfostream member in my logger class. Then you can have a generic templated operator<< that selectively forwards to the embedded stream.

For example:

class Logger;

template<class T> Logger& operator<<(Logger&, const T&);

enum LogLevel
{
    debug,
    info,
    warning,
    error
};

class Logger
{
public:
    void open(const char* file) { stream.open(file); }
    void close() { stream.close(); }
    void passLevel(Loglevel level) { pass = level; }
    void logLevel(LogLevel level) { current = level; }
private:
    bool passThrough() { return current >= pass; }

    std::wofstream stream;
    LogLevel pass;
    LogLevel current;

    friend template<class T> Logger& operator<<(Logger&, const T&);
};

template<class T> 
Logger& operator<<(Logger& log, const T& rhs)
{
    if (log.passthrough())
    {
        log.stream << rhs; 
    }
    return log;
}

Logger& operator<<(Logger&, LogLevel level)
{
    log.logLevel(level);
    return log;
}

struct setLogLevel {
    setLogLevel(LogLevel l) : level(l) { }
    LogLevel level;
};

Logger& operator<<(Logger&, const setLogLevel setter)
{
    log.passLevel(setter.level);
    return log;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文