В C++ строка форматирования опять Часть-2


Ранее спрашивал здесь.

Код теперь доступен на Гитхабе.

После предыдущего обзора я добавил юнит-тесты.

Поскольку он большой, он будет приходить на пару частей.

Часть 1 | Часть 2 | Часть 3 | Часть 4

Часть 2

Это простой вспомогательный объект. Он сохраняет результаты парсинга строки в объект. Таким образом, нам не нужно повторно разобрать строку для информации.

FormatInfo.ч

#ifndef THORSANVIL_IOUTIL_FORMAT_INFO_H
#define THORSANVIL_IOUTIL_FORMAT_INFO_H

#include <iostream>
#include <typeinfo>

namespace ThorsAnvil::IOUtil
{

// Enum representing the Length, specifier and type information provided by the format string
#pragma vera-pushoff
                                                                                // printf doc http://www.cplusplus.com/reference/cstdio/printf/
enum class Length    {none, hh, h, l, ll, j, z, t, L};                          // Use the same values as in printf documentation so it is easy to lookup
enum class Specifier {d, i, u, o, x, X, f, F, e, E, g, G, a, A, c, s, p, n};    // Use the same values as in printf documentation so it is easy to lookup
enum class Type      {Int, UInt, Float, Char, String, Pointer, Count};          // The type we are expecting
enum class Dynamic   {None, Width, Precision, Both};                            // If width and/or precision are specified by parameter
#pragma vera-pop

using AllowedType = std::pair<std::type_info const*, int>;

struct FormatInfo
{
    // Formatter has the text representation:
    //      %<Flag>*<Width>?[.<Precision>]?<Length>?<Specifier>
    //
    //      Flag:       - + <space> # 0
    //      Width:      {1-9}{0-9}*
    //      Precision:  {0-9}*
    //      Length:     hh h l ll j z t L
    //      Specifier:  d i u o x X f F e E g G a A c s p n

    // Flags
    bool                    leftJustify;    // -    Left-justify within the given field width; Right justification is the default (see width sub-specifier).
    bool                    forceSign;      // +    Forces to precede the result with a plus or minus sign (+ or -) even for positive numbers. By default, only negative numbers are preceded with a - sign.
    bool                    forceSignWidth; // (space)  If no sign is going to be written, a blank space is inserted before the value.
    bool                    prefixType;     // #    Used with o, x or X specifiers the value is preceded with 0, 0x or 0X respectively for values different than zero.
                                            //      Used with a, A, e, E, f, F, g or G it forces the written output to contain a decimal point even if no more digits follow. By default, if no digits follow, no decimal point is written.
    bool                    leftPad;        // 0    Left-pads the number with zeroes (0) instead of spaces when padding is specified (see width sub-specifier).
    // Width and precision of the formatter.
    std::size_t             width;
    std::size_t             precision;
    Length                  length;
    Specifier               specifier;

    // Pre-calculate a some values based on the format string
    Type                    type;           // Calculated based on length/specifier
    Dynamic                 useDynamicSize; // Are width/precision dynamically specified.
    AllowedType             expectedType;   // Type info we expect the next argument to be based on length/specifier
    std::ios_base::fmtflags format;         // The format flags that will be applied to stream before the next argument

};

}

#endif


Комментарии
1 ответ

Очень маленький код приглашения очень маленький комментарий. Вот несколько вещей, которые пришли мне на ум:

Включает в себя

Один вопрос, безусловно, что вам не хватает #include <utility> для std::pair, а также #include <cstddef> (или аналогичного) для std::size_t.

Другое дело, что могут сделать некоторые люди злятся на тебя-это то, что вы #include <iostream>. Причина этого заключается в том, что этот заголовок вводит некоторые статические инициализаторы в текущей единице компиляции, которая инициализировать специальной потоков, которая, в свою очередь, приводит к бинарные наворотов и возможной эффективности сокращения (взгляните на ассамблее , что заголовок создает).

На почти все случаи жизни, #include <iostream> можно избежать, в том числе один из несколько других заголовков, в случае #include <ios>, который обеспечивает std::ios_base.

Тьфу, std::type_info

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

Из одного файла, я не могу сказать, является ли это в случае с вашим кодом или нет. Однако, передав указатель на некоторые std::type_info вместе с int делает намек на сомнительных практик. Пожалуйста, пересмотреть ли std::type_info действительно уместно.

Комментарии

// Enum representing the Length, specifier and type information provided by the format string

кажется, грани ненужного мне. Что перечисления представляют собой уже достаточно понятно по их названию, только бита, связывая их на всю строку формата функции не дается в коде (однако, так как заголовок называется FormatInfo.hя бы сказал, эта информация подразумевается).

// printf doc http://www.cplusplus.com/reference/cstdio/printf/
// Use the same values as in printf documentation so it is easy to lookup
// Use the same values as in printf documentation so it is easy to lookup
// The type we are expecting
// If width and/or precision are specified by parameter

Что первый комментарий-это плохо, потому что ссылки на внешние ресурсы подлежат ссылке гниения. Только тогда, когда информация, содержащаяся там, не легко доступны в другом месте. В случае printf параметры это не так; большинство POSIX-совместимых систем даже на странице справочника объясняя их тщательно. Кроме того, использование printf настолько распространена, что я бы сказал, что его допустимо считать пользователи имеют возможность найти документацию самостоятельно.

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

Оба Последние комментарии не на много ценной информации в код, так что я бы сказал, что вы должны опустить их.

Структура

FormatInfo кажется, состоят из трех отдельных "блоков" информации/настроек. Поскольку эти блоки каждый знак определенной категории информации, я бы сделал вложенные структуры для них. Мое предложение будет выглядеть что-то похожее на это:

struct FormatInfo {
struct Flags {
bool leftJustify;
bool forceSignWidth;
bool prefixType;
bool leftPad;
};

struct Dimension {
std::size_t width;
std::size_t precision;
Length length;
Specifier specifier;
};

struct FormatSettings {
Type type;
Dynamic useDynamicSize;
AllowedType expectedType;
std::ios_base::fmtflags format;
};

Flags flags;
Dimension dimension;
FormatSettings formatSettings;
};

который инкапсулирует различные группы параметров лучше.

В зависимости от вашего использования, есть также точки в четырех перечислений от верхней части вашего файла часть FormatInfo если это имеет смысл со структурной точки зрения (опять же, я не обзор всей структуры проекта).


Кроме указанных пунктов, некоторые пункты моего ответа в части 1 , также применяется здесь, например пункт про отступы.

3
ответ дан 5 марта 2018 в 09:03 Источник Поделиться