2009-08-25 2 views
0

Я пытаюсь написать простой класс аудита, который принимает ввод с помощью оператора < < и записывает аудит после получения пользовательского манипулятором, как это:пользовательского поток манипулятором для класса

class CAudit 
{ 
public: 
    //needs to be templated 
    CAudit& operator << (LPCSTR data) { 
     audittext << data; 
     return *this; 
    } 

    //attempted manipulator 
    static CAudit& write(CAudit& audit) { 
     //write contents of audittext to audit and clear it 
     return audit; 
    } 

private: 
    std::stringstream audittext; 
}; 

//to be used like 
CAudit audit; 
audit << "Data " << data << " received at " << time << CAudit::write; 

Я признаю, что перегруженный оператор мой код не возвращает объект потока, но задавался вопросом, возможно ли еще использовать синтаксис манипулятора. В настоящее время компилятор видит «< <» как двоичный оператор сдвига вправо.

Спасибо за любой вклад, Patrick

ответ

4

Чтобы заставить его работать, вы должны добавить перегрузку оператора < < для функций, , чем вызов функции из нее:

class CAudit 
{ 
    //...other details here as in original question 

    CAudit& operator << (CAudit & (*func)(CAudit &)) 
    { 
     return func(*this); 
    } 
}; 

CAudit audit; 
audit << "some text" << CAudit::write; 
+0

Спасибо, строит наконец – Patrick

1

бы это не

class CAudit 
{ 
public: 
    template< typename T > 
    CAudit& operator<<(const T& data) 
    { 
     audittext << data; 
     return *this; 
    } 

    class write {}; 

    void operator<<(const write& data) 
    { 
     /* whatever */ 
    } 

private: 
    std::stringstream audittext; 
}; 

делать то, что вы хотите?

+0

Спасибо за ответ, похоже, что он будет работать подобным образом с ответом Робсона, вероятно, попробует использовать функтор, чтобы избавиться от параметра указателя функции. – Patrick

2

Бинарный оператор сдвига и поток оператора и тот же оператор. Полностью законно перегружать operator + для вашего класса, чтобы написать «Hello world» на std :: cout (хотя это очень плохая идея). Точно так же авторы стандарта C++ решили перегрузить оператор < < для потоков, записываемых в поток.
Вы не ясно писали, в чем проблема. Мое предположение - ошибка компиляции. В этом случае лучше всего привести сообщение об ошибке. Если я прав, проблема в том, что вы определили только оператор < < для LPCSTR, а затем вы хотите, чтобы он работал с функциональным объектом с правой стороны.
Вы используете слово «манипулятор», но вы что-то неправильно понимаете. Манипулятор для потока (поток из STL) - это функция, которая выполняет некоторые действия над потоком, в который он записывается. И он работает только из-за этой перегрузки:

ostream& operator<< (ostream& (*pf)(ostream&)); 

, который принимает функцию и применяет ее к потоку.
Точно так же вам нужно:

CAudit& operator<< (CAudit& (*pf)(CAudit& audit)) 
{ 
    return (*pf)(audit); 
} 
+0

Спасибо за объяснение – Patrick

1

я сделать что-то очень похожее на трассировку, но использовать stringstream. Это гарантирует, что все сторонние лица operator <<() и манипуляторы работают. Я также использую дескриптор вместо манипулятора записи клиента.

class DebugStream 
{ 
public: 
    DebugStream(short level, const char * file, int line) { 
     sstream << "L" << level << "\t" << file << "\t" << line << "\t"; 
    } 
    ~DebugStream() { write(sstream.str()); } 

    std::ostream & stream() { return sstream; } 
private: 
    std::stringstream sstream; 

    DebugStream(const DebugStream &); 
    DebugStream & operator=(const DebugStream &); 
}; 

Это становится доступным с некоторыми макросами:

#define DBG_ERROR if (1<=dbg_level()) DebugStream(1, __FILE__, __LINE__).stream() 
#define DBG_INFO if (2<=dbg_level()) DebugStream(2, __FILE__, __LINE__).stream() 

И код просто использует макросы

DBG_INFO << "print some debug information"; 

Вам не нужен конкретный манипулятор записи для очистки данных в файл журнала. Когда анонимный объект DebugStream выходит за рамки (после того, как элемент управления покидает строку), содержимое автоматически записывается.

Хотя я обычно избегаю макросов, в этом случае использование инструкции if означает, что у вас нет накладных расходов на построение линии трассировки, если вы на самом деле ее не требуете.

Возврат ostream методом stream() позволяет использовать это для глобальных функций-членов, поскольку анонимные объекты не могут передаваться как неконстантные ссылочные параметры.

Смежные вопросы