Пользовательский манипулятор потока для класса
Я пытаюсь написать простой класс аудита, который принимает ввод через оператор < < и записывает аудит после получения настраиваемого манипулятора следующим образом:
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;
Я понимаю, что перегруженный оператор в моем коде не возвращает объект потока, но задавался вопросом, возможно ли еще использовать синтаксис манипулятора. В настоящее время компилятор видит '< < как двоичный оператор сдвига вправо.
Спасибо за любой вклад,
Патрик
Ответы
Ответ 1
Чтобы заставить его работать, вы должны добавить перегрузку оператора < < для функций,
чем вызов функции из него:
class CAudit
{
//...other details here as in original question
CAudit& operator << (CAudit & (*func)(CAudit &))
{
return func(*this);
}
};
CAudit audit;
audit << "some text" << CAudit::write;
Ответ 2
Оператор двоичного сдвига и оператор потока - это тот же самый оператор. Полностью законно перегружать operator + для вашего класса, чтобы написать "Hello world" на std:: cout (хотя это очень плохая идея). Точно так же авторы стандарта С++ решили перегрузить оператор < для потоков как запись в поток.
Вы четко не писали, в чем проблема. Мое предположение - ошибка компиляции. В этом случае лучше всего привести сообщение об ошибке. Если я прав, проблема в том, что вы определили только оператор < < для LPCSTR, а затем вы хотите, чтобы он работал с функциональным объектом с правой стороны.
Вы используете слово "манипулятор", но вы ничего не понимаете. Манипулятор для потока (поток из STL) - это функция, которая выполняет некоторые действия над потоком, в который он записывается. И он работает только из-за этой перегрузки:
ostream& operator<< (ostream& ( *pf )(ostream&));
который принимает функцию и применяет ее к потоку.
Аналогично вам нужно:
CAudit& operator<< (CAudit& ( *pf )(CAudit& audit))
{
return (*pf)(audit);
}
Ответ 3
Не будет ли это
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;
};
делай, что хочешь?
Ответ 4
Я делаю что-то очень похожее на трассировку, но использую 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()
позволяет этому работать для глобальных функций-членов, поскольку анонимные объекты не могут передаваться как неконстантные ссылочные параметры.