Я смотрю в обеспечение ostream
операторы для некоторых математических классов (матрица, вектор и т. д.) Друг заметил, что реализация стандартной библиотеки gcc ostream
оператор для std::complex
включает внутреннее использование строкового потока для форматирования вывода перед передачей его фактическому ostream
:
/// Insertion operator for complex values.
template<typename _Tp, typename _CharT, class _Traits>
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x)
{
basic_ostringstream<_CharT, _Traits> __s;
__s.flags(__os.flags());
__s.imbue(__os.getloc());
__s.precision(__os.precision());
__s << '(' << __x.real() << ',' << __x.imag() << ')';
return __os << __s.str();
}
Этот паттерн виден и в бусте. Мы пытаемся определить, стоит ли следовать этой схеме. Были опасения, что это включает в себя добавление дополнительного заголовка для потока строк, и в потоке строк требуются дополнительные выделения кучи, которых потенциально можно избежать.
Наиболее разумно было предположить, что, если клиенту требуется эта функциональность, он может создать поток строк и выполнить предварительную передачу самостоятельно.
Может ли кто-нибудь помочь мне понять, почему это будет считаться хорошей практикой и должен ли я ее принимать?
Подумайте, что произойдет, если вы установите выходную ширину в ostream, а затем запишите в нее std :: complex — вы не хотите, чтобы ширина влияла только на первую операцию вывода (т.е. '('
персонаж)
std::complex i(0, 1);
std::cout << std::setw(10) << std::left << i;
Это должно напечатать "(0,1) "
не "( 0,1)"
Формируя весь вывод в виде одной строки, затем выписывая его, вывод учитывает ширину поля и другие флаги форматирования, установленные в потоке.
Причина потока, указанная в другом ответе, на самом деле не сработает: строка все еще может быть разделена на уровне буфера потока, потому что эти операции не являются атомарными при вызове из нескольких потоков.
Однако есть два соображения, которые имеют отношение к делу:
width()
количество символов, которое должна занимать вся строка форматирования. Если вы используете операторы вывода внутренне для другого оператора вывода, вы бы сделали первый элемент, занимающий ширину, а не результирующую всю строку, состоящую из нескольких компонентов. Например, для комплексного числа реальный элемент будет занимать width()
а не сочетание реального элемента, запятой и воображаемого элемента.Одна из основных целей этого шаблона — избежать сохранения манипуляторов / флагов исходного потока и сброса их перед возвратом. Boost.IoStateSavers избавляет от необходимости в этом, поэтому я бы сказал, что использование указанной библиотеки было бы лучше.