пользовательский потоковый манипулятор для класса - PullRequest
0 голосов
/ 25 августа 2009

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

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;

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

Спасибо за любой ввод, Патрик

Ответы [ 4 ]

4 голосов
/ 25 августа 2009

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

 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 голосов
/ 25 августа 2009

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

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

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

CAudit& operator<< (CAudit& ( *pf )(CAudit& audit))
{
  return (*pf)(audit);
}
1 голос
/ 25 августа 2009

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

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() позволяет этому работать для глобальных функций-членов, поскольку анонимные объекты не могут быть переданы как неконстантные ссылочные параметры.

1 голос
/ 25 августа 2009

Не так ли

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

делай что хочешь?

...