Это еще одна интересная альтернатива https://github.com/Shy-Ta/expression-evaluator-demo
. Использование очень простое и выполняет задание, например:
ExpressionsEvaluator evalExpr = ExpressionsFactory.create("2+3*4-6/2");
assertEquals(BigDecimal.valueOf(11), evalExpr.eval());
Что вам нужно сделать, так это написать собственный буфер потока:
Когда буфер потока очищается, вы выводите символы префикса и содержимое потока.
Следующее работает, потому что 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
>
Вместо того, чтобы пытаться изменить поведение std::endl
, вам, вероятно, следует создать фильтрующий потоковый буфер для выполнения этой работы. У Джеймса Канзе есть пример , показывающий, как вставить метку времени в начало каждой выходной строки. Он должен потребовать лишь незначительной модификации, чтобы изменить это на любой префикс, который вы хотите в каждой строке.
Ваши перегруженные операторы класса 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;
}
Принципиально согласен с Нилом.
Вы хотите изменить поведение буфера, потому что это единственный способ расширить 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
!
Вы не можете изменить std :: endl
- как следует из названия, он является частью стандартной библиотеки C ++ и его поведение исправлено. Вам нужно изменить поведение самого потока, когда он получает конец строки. Лично я бы не подумал, что это того стоит, но если вы хотите углубиться в эту область, я настоятельно рекомендую прочитать книгу Standard C ++ IOStreams & Locales .