簡體   English   中英

FMT - 如何解析浮點格式 arguments 的 fmt 格式字符串?

[英]FMT - How to parse fmt format string for floating point format arguments?

我想在 fmt 中使用自定義十進制數字類型。 十進制類型使用它自己的方法生成一個 output 字符串。 我無法理解如何解析超出單個字符的上下文字符串,以獲得數字精度等。然后我可以將其發送到字符串方法,以生成相關的 output,然后在返回結果時將其傳遞給字符串格式化程序. 自定義類型不包含原生浮動類型直接格式化。 轉換為本機類型也不起作用,因為小數可能具有比本機類型更大的指數或精度。

根據文檔,我不確定這是可能的。 或者我沒有朝着正確的方向前進。

提前感謝您的任何澄清!

template<>
    struct std::formatter<Number> {

        Format_Args fmt;

        constexpr auto parse(std::format_parse_context& context) {

            auto it = context.begin();
            auto end = context.end();

            if (it != end && (*it == 'f' || *it == 'e')) {
                fmt.type = *it++;
            }

            return it;
        }

        template<typename Context>
        constexpr auto format(const Number n, Context& context) {

            return formatter<std::string>::format(n.to_string(fmt), context);
        }
    };

我查看了 API 文檔,沒有成功。 還查看了 fmt 標記的帖子,尋找答案。 這篇文章,接近我正在尋找的東西。 但沒有評論如何解析多個 arguments 或變量 arguments。

閱讀本教程后想通了。 雖然它沒有直接回答我的問題。 它確實讓我找到了一種方法來捕獲為上下文發送的所有文本格式。

然后我可以在格式化方法中根據需要解析它。 下面是一個簡單的例子,說明如何將解析后的文本捕獲到一個向量中,以便稍后進行處理。 在這里可以簡單地將它們輸出到 std:ostream output。

namespace std {

    struct Color {
        uint8_t r{ 0 };
        uint8_t g{ 0 };
        uint8_t b{ 0 };
    };

    template <>
    struct std::formatter<Color> {

        std::vector<char> context;

        constexpr auto parse(std::format_parse_context& ctx) {

            auto pos = ctx.begin();

            while (pos != ctx.end() && *pos != '}') {
                
                context.push_back(*pos);
                
                ++pos;
            }
            return pos;  // This must be '}'.
        }

        auto format(const Color& col, std::format_context& ctx) {

            bool hex = false;

            for (auto c : context) {
                std::cout << c;

                if (c == '!') {
                    std::cout << "\n";
                }
                
                if (c == 'h' || c == 'H') {
                    hex = true;
                }
            }
            std::cout << std::endl;

            if (hex) {
                uint32_t val = col.r << 16 | col.g << 8 | col.b;
                return std::format_to(ctx.out(), "#{:x}", val);
            }

            return std::format_to(ctx.out(), "({}, {}, {})", col.r, col.g, col.b);
        }
    };
}

int main() {

    Color a;

    std::cout << std::format("{:Hello formatter!.50}", a) << std::endl;
    std::cout << std::endl;
}

導致這個 output:

Hello formatter!
.50
#0

下面是更新的格式化程序,它編譯將解析后的 arguments 傳遞給我的 object class。請注意,所有解析都發生在編譯時。

namespace std {

    template <>
    struct std::formatter<Olly::MPA::Number> {
        /*
            In the base class is a format struct, to capture the relevant data.
            It is defaulted to the argument values below.

            struct Format_Args {
                int  base  = 10;
                char sign  = '-';
                char align = '<';
                int  width = -1;
                int  prec  = -1;
                char type  = 'd';
                char form  = 'g';
                char fill  = '\0';
                bool pref  = false;
                bool pad   = false;
                bool local = false;
            };
        */

        Olly::MPA::Number::Format_Args fmt;

        constexpr auto parse(std::format_parse_context& ctx) {

            bool prec_definition = false;

            std::string arg_buffer;

            auto pos = ctx.begin();

            if (pos != ctx.end() && *pos != '}') {

                char c = *pos;

                if (c != '<' && c != '^' && c != '>') {
                    fmt.fill = c;
                    ++pos;
                }

                if (fmt.fill == '\\' &&  c == '<' || c == '^' || c == '>') {
                    fmt.fill = c;
                    ++pos;
                }
            }

            while (pos != ctx.end() && *pos != '}') {

                char c = *pos;

                switch (c) {

                case '<':
                case '^':
                case '>':
                    fmt.align = c;
                    break;

                case '+':
                case '-':
                case ' ':
                    fmt.sign = c;
                    break;

                case '#':
                    fmt.pref = true;
                    break;

                case '0':
                    fmt.pad = true;
                    break;

                case '.':
                    prec_definition = true;
                    fmt.width = arg_buffer.size() ? std::stoi(arg_buffer) : 0;
                    arg_buffer = "";
                    break;

                case 'L':
                    fmt.local = true;
                    break;

                case 'b':
                case 'B':
                case 'd':
                case 'D':
                case 'o':
                case 'O':
                case 'x':
                case 'X':
                    fmt.type = c;
                    break;

                case 'e':
                case 'E':
                case 'f':
                case 'F':
                case 'g':
                case 'G':
                    fmt.type = c;
                    break;

                default:
                    arg_buffer += c;
                }
                
                ++pos;
            }

            if (prec_definition) {
                fmt.prec = arg_buffer.size() ? std::stoi(arg_buffer) : 0;
            }
            else {
                fmt.width = arg_buffer.size() ? std::stoi(arg_buffer) : 0;
            }

            return pos;
        }

        auto format(const Olly::MPA::Number& a, std::format_context& ctx) {

            return std::format_to(ctx.out(), "{}", a.to_string(fmt));
        }
    };
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM