Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Type-safe 'printf-like' format class

Boost , ,

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

boost.png (6897 bytes)Type-safe 'printf-like' format class

Choices made

«Le pourquoi du comment» («Почему так происходит»)


The syntax of the format-string

Формат – это новая библиотека. Одна из его целей состоит в том, чтобы обеспечить замену printf, что означает, что формат может анализировать строку формата, предназначенную для printf, применять ее к приведенным аргументам и получать тот же результат, что и printf.
С этим ограничением было примерно 3 возможных варианта синтаксиса строки формата:

  1. Используйте тот же синтаксис printf. Он хорошо известен многим опытным пользователям и соответствует практически всем потребностям. Но с потоками C++ характер преобразования типа, решающий для определения конца директивы, полезен только для установки некоторых связанных вариантов форматирования в контексте потоков C++ (%x для настройки hexa и т. Д.). Лучше было бы сделать этот обязательный тип-конверсионный характер, с измененным смыслом, факультативным.
  2. Расширяйте синтаксис printf, сохраняя совместимость, используя символы и конструкции, которые еще не действительны в качестве синтаксиса printf. Например: "%1%", "%", "% | 1$d |", .. Используя знаки начала / конца, можно рассмотреть все виды расширения.
  3. Обеспечить режим неунаследованности, параллельно с типографско-совместимым, который может быть разработан, чтобы соответствовать другим целям без ограничений совместимости с существующим синтаксисом. Но проектирование замены синтаксиса printf, которая была бы явно лучше и мощнее, является еще одной задачей, чем создание класса формата. Когда такой синтаксис разработан, мы должны рассмотреть разделение Boost.format на 2 отдельные библиотеки: одна работает рука об руку с этим новым синтаксисом, а другая поддерживает устаревший синтаксис (возможно, быстрая версия, построенная с улучшением безопасности выше snprintf или тому подобное).
In the absence of a full, clever, new syntax clearly better adapted to C++ streams than printf, the second approach was chosen. Boost.format uses printf's syntax, with extensions (tabulations, centered alignements) that can be expressed using extensions to this syntax.
And alternate compatible notations are provided to address the weaknesses of printf's :
  • «%Nкак более простое позиционное, бесхарактерное и необязательное обозначение.
  • % |spec |как способ инкапсулировать директиву printf в визуально видимые структуры movre, в то же время делая опциональным тип-конверсионный характер printf.

Why are arguments passed through an operator rather than a function call ?


The inconvenience of the operator approach (for some people) is that it might be confusing. It's a usual warning that too much of overloading operators gets people real confused.
Since the use of format objects will be in specific contexts ( most often right after a "cout << ") and look like a formatting string followed by arguments indeed :
format(" %s at %s  with %s\n") % x % y % z;
we can hope it wont confuse people that much.

Другой страх перед операторами — проблемы с приоритетом. Что делать, если я когда-нибудь напишуформат("%s") % x+y
вместоформата («%s») % (x+y)???
Он допустит ошибку во время компиляции, поэтому ошибка будет немедленно обнаружена.
Действительно, эта линия вызываетtmp = оператор%(формат("%s"), x)
, а затемоператор +(tmp, y)
tmp будет объектом формата, для которого не определено неявное преобразование, и, таким образом, вызов оператору + потерпит неудачу. (если, конечно, вы не определили такого оператора). Таким образом, вы можете с уверенностью предположить, что ошибки приоритета будут замечены при составлении.


С другой стороны, функциональный подход имеет истинное неудобство. Он должен определить множество шаблонных функций, таких как:

template <class T1, class T2,  .., class TN> 
string format(string s,  const T1& x1, .... , const T1& xN);
and even if we define those for N up to 500, that is still a limitation, that C's printf does not have.
Also, since format somehow emulates printf in some cases, but is far from being fully equivalent to printf, it's best to use a radically different appearance, and using operator calls succeeds very well in that !


В любом случае, если мы действительно выберем формальную систему шаблонов вызовов функций, она сможет печатать только классы T, для которых существует

operator<< ( stream,   const T&)
Because allowing both const and non const produces a combinatorics explosion - if we go up to 10 arguments, we need 2^10 functions.
(providing overloads on T& / const T& is at the frontier of defects of the C++ standard, and thus is far from guaranteed to be supported. But right now several compilers support those overloads)
There is a lot of chances that a class which only provides the non-const equivalent is badly designed, but yet it is another unjustified restriction to the user.
Also, some manipulators are functions, and can not be passed as const references. The function call approach thus does not support manipulators well.

Использование выделенного двоичного оператора является самым простым, самым надежным и наименее ограничивающим механизмом для передачи аргументов, когда вы не можете знать количество аргументов во время компиляции.


Why operator% rather than a member function 'with(..)' ??

technically,
format(fstr) % x1 % x2 % x3;
has the same structure as
format(fstr).with( x1 ).with( x2 ).with( x3 );
which does not have any precedence problem. The only drawback, is it's harder for the eye to catch what is done in this line, than when we are using operators. calling .with(..), it looks just like any other line of code. So it may be a better solution, depending on tastes. The extra characters, and overall cluttered aspect of the line of code using 'with(..)' were enough for me to opt for a true operator.

Why operator% rather than usual formatting operator<< ??

  • потому, что передача аргументов объекту формата не является тем же самым, что отправка переменных последовательно в поток, и потому, что объект формата не является потоком или манипулятором.
    Мы используем оператора для передачи аргументов. Формат будет использовать их как функцию, он просто принимает аргументы один за другим.
    Объекты формата не могут обеспечить потоковое поведение. Когда вы пытаетесь реализовать объект формата, который действует как манипулятор, возвращая поток, вы заставляете пользователя поверить, что он полностью похож на потоковый манипулятор. И рано или поздно пользователь обманывается этой точкой зрения.
    Наиболее очевидным примером такой разницы в поведении является
    .
    cout << format("%s %s ") << x;
    cout << y ;  // uh-oh, format is not really a stream manipulator
    
  • precedence of % is higher than that of <<. It can be viewd as a problem, because + and - thus needs to be grouped inside parentheses, while it is not necessary with '<<'. But if the user forgets, the mistake is catched at compilation, and hopefully he won't forget again.
    On the other hand, the higher precedence makes format's behaviour very straight-forward.
    cout << format("%s %s ") % x % y << endl;
    
    is treated exaclt like :
    cout << ( format("%s %s ") % x % y ) << endl;
    
    So using %, the life of a format object does not interfere with the surrounding stream context. This is the simplest possible behaviour, and thus the user is able to continue using the stream after the format object.

    With operator<<, things are much more problematic in this situation. This line :
    cout << format("%s %s ") <<  x  <<  y << endl;
    
    is understood as :
    ( ( ( cout << format("%s %s ") ) << x ) <<  y ) << endl;
    
    Several alternative implementations chose operator<<, and there is only one way to make it work :
    the first call to
    operator<<( ostream&, format const&)
    
    returns a proxy, encapsulating both the final destination (cout) and the format-string information
    Passing arguments to format, or to the final destination after completion of the format are indistinguishable. This is a problem.

    Я рассмотрел несколько возможных реализаций, и ни одна из них не является полностью удовлетворительной.
    Например: Чтобы уловить ошибку пользователя, имеет смысл делать исключения, когда пользователь передает слишком много аргументов. Но в этом контексте дополнительные аргументы, безусловно, направлены на конечный пункт назначения. Здесь есть несколько вариантов:

    • You can give-up detection of arity excess, and have the proxy's template member operator<<( const T&) simply forward all supplementary arguments to cout.
    • Требовать от пользователя закрыть формат аргументов специальным манипулятором, 'endf', таким образом:
      cout << format("%s %s ") <<  x  <<  y << endf << endl;
      
      Вы можете определить endf как функцию, которая возвращает конечный пункт назначения, хранящийся внутри прокси. Тогда все в порядке, после эндфа пользователь снова звонит<< на кут.
    • Промежуточное решение заключается в том, чтобы адресовать наиболее частое использование, где пользователь просто хочет вывести еще один элемент манипулятора на кут (std::flush, или endl, ..)
      cout << format("%s %s \n") <<  x  <<  y << flush ;
      
      Тогда решение заключается в перегрузке оператора для манипуляторов. Таким образом, вам не нужен эндф, но вывод неманипулятора сразу после аргументов формата является ошибкой.

    The most complete solution is the one with the endf manipualtor. With operator%, there is no need for this end-format function, plus you instantly see which arguments are going into the format object, and which are going to the stream.
  • Эстетически: «%» — это та же буква, что и в строке формата. Очень приятно, что для каждого аргумента используется одно и то же письмо. '<<' - 2 буквы, '%' - одна. '%' также меньше по размеру. Он в целом улучшает визуализацию (мы видим, что с чем) :
    cout << format("%s %s %s") %x %y %z << "And  avg is" << format("%s\n") %avg;
    
    по сравнению с :
    cout << format("%s %s %s") << x << y << z << endf <<"And avg is" << format("%s\n") << avg;
    
    «<<» вводя в заблуждение ставит аргументы на тот же уровень, что и любой объект, переданный потоку.
  • Python также использует % для форматирования, поэтому вы видите, что это не так «неслыханно»

Why operator% rather than operator(), or operator[] ??

Оператор() имеет право быть естественным способом передачи аргумента в функцию. Некоторые считают, что значение оператора хорошо применимо к использованию в формате.
Технически они не хуже оператора, но довольно уродливы. (Это вопрос вкуса)
И в глубине души использование оператора% для передачи аргументов, на которые ссылались «%» в строке формата, кажется мне гораздо более естественным, чем использование этих операторов.


Valid HTML 4.01 Transitional

Пересмотрено02 Декабря 200602 December, 2006[ORIG_END] -->

Авторское право и копия; 2001 Сэмюэл Кремпп

Распространяется по лицензии Boost Software License, версия 1.0. (См. сопроводительный файлLICENSE_1_0.txtили копию на) http://www.boost.org/LICENSE_1_0.txt

Статья Type-safe 'printf-like' format class раздела может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 04:50:15/0.0073239803314209/1