Простой класс регистрации wostream (с пользовательскими потоковыми манипуляторами) - PullRequest
3 голосов
/ 12 ноября 2010

Я читал тонны вопросов, статей и документации, но я не нашел решения своей проблемы.

Я хотел бы создать простой класс для использования при отладке.Конечный результат, который позволил бы мне сделать что-то вроде этого:

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' (или нет приемлемого преобразования) "</p>

Любая помощь приветствуется.

Спасибо!

Ответы [ 3 ]

0 голосов
/ 12 ноября 2010

Проблема в том, что когда вы делаете это:

test << "Setting state!"

Возвращает базовый объект Wostream.Таким образом, цепочка не работает, поскольку нет перегрузки для:

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

Однако вы можете сделать это в отдельных строках, например:

test << "Setting state!";
test << doSetState(1) << endl;
0 голосов
/ 12 ноября 2010

Я бы пошел немного по-другому.

Вместо того, чтобы наследовать от std::wostream, у меня в классе логгера будет std::wfostream член. Тогда у вас может быть шаблонный шаблон 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;
}
0 голосов
/ 12 ноября 2010

Ваш оператор ostream не имеет правильной подписи. Должно быть:

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

(Необходимо использовать ссылку, потому что однопроходный компилятор не знает размер doSetState, когда он находится в середине определения класса.)

...