Перегрузка обработки std :: endl?

Это еще одна интересная альтернатива https://github.com/Shy-Ta/expression-evaluator-demo

. Использование очень простое и выполняет задание, например:

  ExpressionsEvaluator evalExpr = ExpressionsFactory.create("2+3*4-6/2");  
  assertEquals(BigDecimal.valueOf(11), evalExpr.eval()); 

30
задан OmarOthman 15 March 2012 в 10:30
поделиться

5 ответов

Что вам нужно сделать, так это написать собственный буфер потока:
Когда буфер потока очищается, вы выводите символы префикса и содержимое потока.

Следующее работает, потому что std :: endl вызывает следующее.

1) Добавьте к потоку '\ n'.
2) Вызывает flush () в потоке
2a) Это вызывает pubsync () в буфере потока.
2b) Это вызывает виртуальный метод sync ()
2c) Переопределите этот виртуальный метод для выполнения нужной работы.

#include <iostream>
#include <sstream>

class MyStream: public std::ostream
{
    // Write a stream buffer that prefixes each line with Plop
    class MyStreamBuf: public std::stringbuf
    {
        std::ostream&   output;
        public:
            MyStreamBuf(std::ostream& str)
                :output(str)
            {}
            ~MyStreamBuf() {
                if (pbase() != pptr()) {
                    putOutput();
                }
            }

        // When we sync the stream with the output. 
        // 1) Output Plop then the buffer
        // 2) Reset the buffer
        // 3) flush the actual output stream we are using.
        virtual int sync() {
            putOutput();
            return 0;
        }
        void putOutput() {
            // Called by destructor.
            // destructor can not call virtual methods.
            output << "[blah]" << str();
            str("");
            output.flush();
        }
    };

    // My Stream just uses a version of my special buffer
    MyStreamBuf buffer;
    public:
        MyStream(std::ostream& str)
            :std::ostream(&buffer)
            ,buffer(str)
        {
        }
};


int main()
{
    MyStream myStream(std::cout);
    myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
}

> ./a.out
[blah]123 
[blah]56 
[blah]78
>
32
ответ дан 27 November 2019 в 22:18
поделиться

Вместо того, чтобы пытаться изменить поведение std::endl, вам, вероятно, следует создать фильтрующий потоковый буфер для выполнения этой работы. У Джеймса Канзе есть пример , показывающий, как вставить метку времени в начало каждой выходной строки. Он должен потребовать лишь незначительной модификации, чтобы изменить это на любой префикс, который вы хотите в каждой строке.

1
ответ дан 27 November 2019 в 22:18
поделиться

Ваши перегруженные операторы класса MyStream должны установить флаг previous-prin-token-was-endl.

Затем, если следующий объект напечатан, перед ним можно вставить [бла] .

std :: endl - это функция, принимающая и возвращающая ссылку на std :: ostream . Чтобы обнаружить, что он был перемещен в ваш поток, вы должны перегрузить оператор << между вашим типом и такой функцией:

MyStream& operator<<( std::ostream&(*f)(std::ostream&) )
{
    std::cout << f;

    if( f == std::endl )
    {
        _lastTokenWasEndl = true;
    }

    return *this;
}
18
ответ дан 27 November 2019 в 22:18
поделиться

Принципиально согласен с Нилом.

Вы хотите изменить поведение буфера, потому что это единственный способ расширить iostreams. endl делает следующее:

flush(__os.put(__os.widen('\n')));

widen возвращает один символ, поэтому вы не можете поместить туда свою строку. put вызывает putc , который не является виртуальной функцией и только изредка перехватывает переполнение . Вы можете выполнить перехват на flush , который вызывает синхронизацию буфера . Вам нужно будет перехватить и изменить все символы новой строки, так как они overflow ed или вручную sync ed, и преобразовать их в вашу строку.

Разработка класса буфера отмены является сложной задачей, потому что basic_streambuf ожидает прямого доступа к своей буферной памяти. Это мешает вам легко передавать запросы ввода-вывода в уже существующий basic_streambuf . Вам нужно рискнуть и предположить, что вы знаете класс буфера потока и унаследовали его. ( cin и cout не гарантируют использование basic_filebuf , насколько я могу судить.) Затем просто добавьте виртуальное переполнение и синхронизацию . (См. §27.5.2.4.5 / 3 и 27.5.2.4.2 / 7.) Выполнение замены может потребовать дополнительного места, поэтому будьте осторожны, чтобы выделить его заранее.

- ИЛИ -

Просто объявите новый endl в своем собственном пространстве имен или, лучше, манипулятор, который вообще не называется endl !

2
ответ дан 27 November 2019 в 22:18
поделиться

Вы не можете изменить std :: endl - как следует из названия, он является частью стандартной библиотеки C ++ и его поведение исправлено. Вам нужно изменить поведение самого потока, когда он получает конец строки. Лично я бы не подумал, что это того стоит, но если вы хотите углубиться в эту область, я настоятельно рекомендую прочитать книгу Standard C ++ IOStreams & Locales .

0
ответ дан 27 November 2019 в 22:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: