Класс формата<<boost/format.hpp>>обеспечивает типоподобное форматирование, безопасным способом, который позволяет выводить определенные пользователем типы.
Объект формата строится из строки формата, а затем приводится аргументация посредством повторных вызовов оператору%.. Каждый из этих аргументов затем преобразуется в строки, которые, в свою очередь, объединяются в одну строку, согласно строке формата.
При вызовеформата (форматов), где s — строка формата, он конструирует объект, который парсирует строку формата и ищет в ней все директивы и готовит внутренние структуры к следующему шагу.
Затем, либо сразу, как в
cout << format("%2% %1%") % 36 % 77;
, либо позже, как в
format fmter("%2% %1%");
fmter % 36; fmter % 77;
, выподаетепеременные в форматтер. эти переменные сбрасываются во внутренний поток, состояние которого устанавливается в соответствии с заданными параметрами форматирования в строке формата - если таковые имеются - и объект формата хранит результаты строки для последнего шага.
После подачи всех аргументов вы можете сбросить объект формата в поток или получить его значение строки, используя функциюstr(), или бесплатную функциюstr(const format&)в пространстве именboost. Строка результата остается доступной в объекте формата до тех пор, пока не будет принят другой аргумент, и в это время она будет восстановлена.
// fmter was previously created and fed arguments, it can print the result :
cout << fmter ;
// You can take the string result :
string s = fmter.str();
// possibly several times :
s = fmter.str( );
// You can also do all steps at once :
cout << boost::format("%2% %1%") % 36 % 77;
// using the str free function :
string s2 = str( format("%2% %1%") % 36 % 77 );
Опционально, после этапа 3, вы можете повторно использовать объект формата и перезапустить на этапе 2 :fmter % 18 % 39; для форматирования новых переменных с той же строкой формата, сохраняя дорогостоящую обработку, участвующую на этапе 1.
All in all, the format class translates a format-string (with
eventually printf-like directives) into operations on an internal stream,
and finally returns the result of the formatting, as a string, or directly
into an output stream.
Examples
using namespace std;
using boost::format;
using boost::io::group;
Манипуляторы применяются при каждом возникновении %1%, и таким образом он печатает: «_+101_+101\n»
Новая функция форматирования: «абсолютные таблицы», полезные внутри петель, для обеспечения того, чтобы поле печаталось в одном положении от одной строки к другой, даже если ширина предыдущих аргументов может сильно различаться.
for(unsigned int i=0; i < names.size(); ++i)
cout << format("%1%, %2%, %|40t|%3%\n") % names[i] % surname[i] % tel[i];
Для некоторых std::vectorимена,фамилииител(см. sample_new_features.cpp) он печатает :
Marc-François Michel, Durand, +33 (0) 123 456 789
Jean, de Lattre de Tassigny, +33 (0) 987 654 321
sample_new_features.cppиллюстрирует несколько функций форматирования, которые были добавлены в синтаксис printf, такие как простые позиционные директивы, центрированное выравнивание и «табулации».
sample_advanced.cppдемонстрирует использование расширенных функций, таких как повторное использование и модификация, форматирование объектов и т.д.
Иsample_userType.cppпоказывает поведение библиотекиформатана определяемых пользователем типах.
Формат-струнасодержит текст, в котором специальные директивы будут заменены строками, вытекающими из форматирования данных аргументов. Унаследованный синтаксис в мирах C и C++ — это тот, который используется printf, и, таким образом, формат может использовать прямые строки формата printf и производить тот же результат (почти во всех случаях). смотретьНесоответствия с printfдля деталей Этот основной синтаксис был расширен, чтобы позволить новые функции, а также адаптироваться к контексту потоков C++. Таким образом, формат принимает несколько форм директив в строках формата:
Наследие строк формата printf :%spec, гдеspecявляется спецификацией форматаprintf specпередает параметры форматирования, такие как ширина, выравнивание, числовое основание, используемое для форматирования чисел, а также другие конкретные флаги. Но классическийтипоспецифическийфлаг printf имеет более слабое значение в формате. Он просто устанавливает соответствующие флаги во внутреннем потоке и/или параметры форматирования, но не требует, чтобы соответствующий аргумент был определенного типа. например: спецификация2$x, означающая «аргумент печати No 2, который является интегральным числом, в hexa» для printf, просто означает «аргумент печати 2 с флагами потокового базового поля, установленными наhex» для формата.
% |спецификация|, гдеспецификацияявляется спецификацией формата printf. Этот синтаксис, очерченный трубами, вводится для улучшения читаемости строки формата, но в первую очередь для того, чтобы сделать символ преобразованиятипанеобязательным в спецификации. Эта информация не нужна с переменными C++, но с прямым синтаксисом printf, необходимо всегда давать символ преобразования типа, просто потому, что этот символ имеет решающее значение для определения конца спецификации формата. например: «% | 5 |» будет форматировать следующую переменную с шириной, установленной на 5, и левым выравниванием точно так же, как следующие директивы printf: «%-5g», «%-5f», «%-5s».
%N%
This simple positional notation requests the formatting of the
N-th argument - wihout any formatting option.
(It's merely a shortcut to Printf's positional directives (like
"%N$s"), but a major benefit is that it's much more readable, and
does not use a "type-conversion" character)
On top of the standard printf format specifications, new features were
implemented, like centered alignment. See new
format specification for details.
printf format specifications
Спецификации формата printf, поддерживаемые Boost.format, соответствуют Unix98. Open-group printfточный синтаксис, а не стандартный C printf, который не поддерживает позиционные аргументы. (Обычные флаги имеют одинаковое значение в обоих, поэтому это не должно быть головной болью для кого-либо) Обратите внимание, что использование спецификаций позиционного формата(например,%3$+d)смешивается с непозиционными(например,%+d)в одной строке формата является ошибкой. В спецификации Open-group ссылка на один и тот же аргумент несколько раз (например,"%1$d%1$d") имеет неопределенное поведение. Поведение Boost.format в таких случаях заключается в том, чтобы каждый аргумент перекликался с любым количеством раз. Единственным ограничением является то, что он ожидает точноPаргументов,Pявляется максимальным числом аргументов, используемым в строке формата. (например, для "%1$d%10$d",P== 10 ). Подача большего или меньшего количества аргументовРвызывает исключение. (если не указано иное, см.исключения)
Поля, заключенные в квадратные скобки, являются необязательными. Каждое из этих полей объясняется по одному в следующем списке:
N$(необязательное поле) указывает, что спецификация формата применяется к аргументуN.Спецификация позиционного формата Если этого нет, аргументы принимаются один за другим. (и это ошибка, чтобы позже предоставить номер аргумента)
flags is a sequences of any of those :
Флаг
Значение
Воздействие на внутренний поток
'-'
левое выравнивание
N/A (применяется позже в строке)
'='
центрированное выравнивание
N/A (применяется позже на строке) - примечание: добавленная функция, не в printf -
'_'
внутреннее выравнивание
устанавливает внутреннее выравнивание - примечание: добавленная функция, не в printf -
'+'
Показать знак даже для положительных чисел
[править править код]
'#'
показать числовое основание и десятичную точку
,,,,,,.
'0'
Площадка с 0 (вставлена после знака или базового индикатора)
Если не выровняется слева, вызываетsetfill('0')и устанавливаетвнутренний Дополнительные действия предпринимаются после преобразования потока для обработкиопределяемого пользователем вывода.
'+'
Если строка не начинается с+или-, вставьтепространствоперед преобразованной строкой
N/A (применяется позже в строке)
Different to printf's behaviour : it is not affected by internal
alignment
ширинаопределяет минимальную ширину для струны, получающейся в результате преобразования. Если необходимо, строка будет проложена с выравниванием и заполнением символов либо установлена на потоке через манипуляторы, либо указана строкой формата (например, флаги '0', '-', ..) Обратите внимание, что ширина не просто устанавливается на потоке преобразования. Для поддержки выводаопределяемых пользователем типов(которые могут вызыватьоператора<<много раз на нескольких элементах) ширина обрабатывается после преобразования потока всего объекта аргумента в код класса формата.
При выводе числа плавающего типа он устанавливает максимальное количество цифр
после десятичной точки, когда в фиксированном или научном режиме
в общем, когда в режиме по умолчаниюобщий режим', как%g
При использовании с тип-чаромsилиSтребуется другое значение: конверсионная строка усечена доточностипервых загонов. (Обратите внимание, что после усечения делается прокладка доширины.)
type-char. it does not impose the concerned argument to
be of a restricted set of types, but merely sets the flags that are
associated with this type specification.
Тип-Чар
Значение
Воздействие на поток
p или x
шестидесятичный выход
гекс
О
октальный выход
окт
е
научный формат
Устанавливает биты флоатфилданаучным
f
формат фиксированного поплавка
Устанавливает биты флоатфилда нафиксированный
г
Общий формат -default- float
unsetвсе биты флоатфилда
X, EилиG
Тот же эффект, что и их строчные аналоги, но с использованием строчных букв для вывода чисел. (экспоненты, шестизначные цифры, ..)
те же эффекты, что'x','e', или'g',плюсверхний регистр
d, iилиu
десятичныйвыходной тип
Устанавливает биты базового поля наdec
sилиS
струнный выход
точностьспецификация не установлена, и ее значение переходит во внутреннее поле для последующего усечения.Точностьобъяснение выше
cилиC
1-символьный выход
Используется только первый символ строки преобразования.
%
напечатать символ%
N/A
Обратите внимание, что спецификация типа «n» игнорируется (и поэтому является соответствующим аргументом), потому что она не подходит в этом контексте. Также поддерживаются модификаторы printf 'l', 'L' или 'h' (для обозначения широких, длинных или коротких типов) (и просто не оказывают влияния на внутренний поток).
new format-specifications
Как указано в таблице флагов, были добавлены центрированные и внутренние флаги выравнивания=и_.
%{nt}, гдеnявляется положительным числом, вставляетабсолютную таблицу. Это означает, что при необходимости формат будет заполнять строку символами, пока длина строки, созданной до сих пор, не достигнетnсимволов. (см.примеры)
% |nTX|вставляет табуляцию таким же образом, но используяXв качестве символа заполнения вместо текущего «заполняющего» шара потока (который являетсяпространствомдля потока в состоянии по умолчанию)
Differences of behaviour vs printf
Suppose you have variables
x1, x2 (built_in types, supported by C's printf),
and a format string s intended for use with a printf function this
way :
printf(s, x1, x2);
In almost all cases, the result will be the same as with this command :
cout << format(s) % x1 % x2;
Но поскольку некоторые спецификации формата printf плохо переводятся в параметры форматирования потоков, есть несколько заметных недостатков в том, как Boost.format эмулирует printf. В любом случае классформатадолжен спокойно игнорировать неподдерживаемые опции, так что строки формата printf всегда принимаются форматом и производят почти такой же выход, как printf.
Here is the full list of such differences :
'0'и''опции: printf игнорирует эти опции для нечисловых преобразований, но формат применяет их ко всем типам переменных. (Таким образом, можно использовать эти опции на определенных пользователем типах, например, рациональный класс и т.д.)
точностьдля аргументов интегральных типов имеет особое значение для printf : printf("(%5.3d)", 7) ;prints « (007) » Формат, как и потоки, игнорирует точный параметр для преобразования интегральных типов.
Вариантprintfс тысячами групповых символовне имеет эффекта в формате.
Ширина или точность, установленные на звездочку*, используются printf для чтения этого поля из аргумента. Например,printf("%1$d:%2$.*3$d:%4$.*3$d\n", час, минута, точность, сек); Этот класс пока не поддерживает этот механизм. Таким образом, такие поля точности или ширины незаметно игнорируются при разборе.
Also, note that the special 'n' type-specification (used to
tell printf to save in a variable the number of characters output by the
formatting) has no effect in format.
Thus format strings containing this type-specification should produce the
same converted string by printf or format. It will not cause differences in
the formatted strings between printf and format.
To get the number of characters in the formatted string using Boost.Format,
you can use the size() member function :
format formatter("%+5d");
cout << formatter % x;
unsigned int n = formatter.size();
User-defined types output
Все флаги, переведенные в состояние потока, действуют рекурсивно в определенных пользователем типах. (флаги остаются активными, как и опция желаемого формата для каждой из операций, которые могут быть вызваны классом, определенным пользователем)
e.g., with a Rational class,
we would have something like :
Это другая история для других вариантов форматирования. Например, ширина установки относится к конечному выходу, произведенному объектом, а не к каждому из его внутренних выходов, и это хорошо:
cerr << format("%-8d") % ratio; // -> "16/9 " and not "16 /9 "
cerr << format("%=8d") % ratio; // -> " 16/9 " and not " 16 / 9 "
Но так же происходит с опциями 0 и '' (в отличие от '+', которые непосредственно переводятся в состояние потокаshowpos. Но таких флагов для нулевых и космических вариантов печати не существует , и это менее естественно:
It is possible to obtain a better behaviour by carefully
designing the Rational's operator<< to handle the stream's
width, alignment and showpos paramaters by itself. This is
demonstrated in sample_userType.cpp.
Manipulators, and internal stream state
Состояние внутреннего потока форматасохраняется до и восстанавливается после вывода аргумента; поэтому модификаторы не липкие и влияют только на аргумент, к которому они применяются. Состояние по умолчанию для потоков, как указано в стандарте: точность 6, ширина 0, правильное выравнивание и десятичный флаг.
Состояние внутреннего потокаформатаможет быть изменено манипуляторами, переданными вместе с аргументом; через функциюгруппы, например:
При прохождении N предметов внутри «группы» увеличивается. Формат должен обрабатывать манипуляторы дифференцированно от обычного аргумента, и, таким образом, использование группы зависит от следующих ограничений:
объект, подлежащий печати, должен быть передан в качестве последнего элемента в группе;
Первые элементы N-1 рассматриваются как манипуляторы, и если они производят продукцию, она выбрасывается.
Такие манипуляторы передаются в потоки прямо перед следующим аргументом, при каждом происшествии. Обратите внимание, что параметры форматирования, указанные в строке формата, перекрываются модификаторами состояния потока, прошедшими таким образом. Например, в следующем коде манипуляторhexимеет приоритет надdспецификацией типа в строке формата, которая задает десятичный выход:
printfявляется классической альтернативой, которая не является безопасной по типу и не может быть распространена на определенные пользователем типы.
ofrstream.cc по дизайну Карла Нельсона был большим источником вдохновения для этого класса форматов.
Библиотека Джеймса Канзе имеет класс форматов (вsrcode/Extended/format), который выглядит очень хорошо отполированным. Его дизайн имеет общее с этим классом использование внутреннего потока для фактических преобразований, а также использование операторов для передачи аргументов. (но в его классе, как и в случае с rstream, используетсяоператор, а неоператор).
Библиотека Карла Нельсонабыла задумана как демонстрация альтернативных решений в дискуссиях по списку Бута для дизайна Boost.format.
Exceptions
Повышаю. Формат обеспечивает соблюдение ряда правил использования объектов формата. Формат-струна должна подчиняться синтаксису, описанному выше, пользователь должен предоставить точно нужное количество аргументов перед выводом в конечный пункт назначения, а при использовании change_item или bind_arg индекс элементов и аргументов не должен быть вне диапазона. Когда формат обнаруживает, что одно из этих правил не выполняется, возникает соответствующее исключение, чтобы ошибки не оставались незамеченными и не устранялись. Но пользователь может изменить это поведение в соответствии со своими потребностями и выбрать, какие типы ошибок могут вызвать исключения, используя следующие функции:
unsigned char exceptions(unsigned char newexcept); // query and set
unsigned char exceptions() const; // just query
Пользователь может вычислить аргумент, за исключением, объединив следующие атомы с помощью двоичной арифметики:
boost::io::bad_format_string_bitвыбирает ошибки из-за плохо сформированных строк формата.
boost::io::too_few_args_bitвыбирает ошибки из-за запроса результата сортировки до того, как все аргументы будут приняты.
boost::io::too_many_args_bitвыбирает ошибки из-за слишком большого количества аргументов.
boost::io::out_of_range_bitвыберите ошибки из-за индекса вне диапазона, предоставленного пользователем при вызовеchange_itemили других функций, принимающих индекс элемента (или индекс аргумента)
boost::io::all_error_bitsВсе ошибки
boost::io::no_error_bitsНе допускает ошибок.
Например, если вы не хотите, чтобы Boost.format обнаруживал плохое количество аргументов, вы можете определить конкретную функцию обертки для построения объектов формата с правильными настройками исключений:
Производительность импульса::формат для форматирования нескольких аргументов встроенного типа с переупорядочением можно сравнить с таковым у Posix-printf и эквивалентных операций ручного потока, чтобы дать меру понесенных накладных расходов. Результат может сильно зависеть от компилятора, реализации стандартной библиотеки и точного выбора строки формата и аргументов.
Поскольку реализация общих потоков в конечном итоге вызывает функции семейства printf для фактического форматирования чисел, в целом printf будет заметно быстрее, чем операции прямого потока. И из-за накладных расходов на переупорядочение (распределения для хранения частей строки, инициализации потока при каждом форматировании элемента, ..) операции прямого потока будут быстрее, чем импульс::формат (один кас ожидает соотношение от 2 до 5 или более)
При итерации форматирования является узким местом производительности, производительность может быть немного увеличена путем разбора строки формата в объект формата и копирования его при каждом форматировании следующим образом.
namespace boost {
template<class charT, class Traits=std::char_traits<charT> >
class basic_format
{
public:
typedef std::basic_string<charT, Traits> string_t;
typedef typename string_t::size_type size_type;
basic_format(const charT* str);
basic_format(const charT* str, const std::locale & loc);
basic_format(const string_t& s);
basic_format(const string_t& s, const std::locale & loc);
basic_format& operator= (const basic_format& x);
void clear(); // reset buffers
basic_format& parse(const string_t&); // clears and parse a new format string
string_t str() const;
size_type size() const;
// pass arguments through those operators :
template<class T> basic_format& operator%(T& x);
template<class T> basic_format& operator%(const T& x);
// dump buffers to ostream :
friend std::basic_ostream<charT, Traits>&
operator<< <> ( std::basic_ostream<charT, Traits>& , basic_format& );
// Choosing which errors will throw exceptions :
unsigned char exceptions() const;
unsigned char exceptions(unsigned char newexcept);
// ............ this is just an extract .......
}; // basic_format
typedef basic_format<char > format;
typedef basic_format<wchar_t > wformat;
// free function for ease of use :
template<class charT, class Traits>
std::basic_string<charT,Traits> str(const basic_format<charT,Traits>& f) {
return f.str();
}
} // namespace boost
Rationale
Цель этого класса состоит в том, чтобы обеспечить лучший, C++, типобезопасный и расширяемыйprintfэквивалент для использования с потоками.
Precisely, format was designed to provide the following
features :
поддержка позиционных аргументов (требуется для интернационализации);
Принять неограниченное количество аргументов.
Сделайте команды форматирования визуально естественными.
Поддерживать использование манипуляторов для изменения отображения аргумента. В дополнение к синтаксису формат-струна.
принимать любые типы переменных, полагаясь на потоки для фактического преобразования в строку. Это особенно касается определенных пользователем типов, для которых эффекты вариантов форматирования должны быть интуитивно естественными.
обеспечивают совместимость с типом, насколько это имеет смысл в безопасном и расширяемом по типу контексте.
В процессе проектирования возникло много проблем, и был сделан выбор, который может быть интуитивно неправильным. Но в каждом случае они были приняты понекоторым причинам.
Credits
Автором формата Boost является Самуэль Кремпп. Он использовал идеи из форматов Rüdiger Loos.hpp и Карла Нельсона.
Пересмотрено02 Декабря 200602 December, 2006[ORIG_END] -->
Статья The Boost Format library раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.