C++23 将 mdspan 格式化为矩阵

问题描述 投票:0回答:1

我正在尝试指定一个格式化程序来将 2 级的

mdspan
打印为矩阵,非常有用。我至少希望元素格式能够工作,例如
std::println("{::.2e}", matrix)
将打印一些双精度矩阵,其格式为
.2e
。困难在于这必须在编译时完成,我不明白这通常是如何完成的,
"{:" + std::string{spec} + "}"
这里不是编译时所以它失败了。了解这是如何完成的或获取实现格式化的一般提示会很有用。

#include <print>
#include <mdspan>
#include <format>

template<class T, class Extents, class Layout, class Accessor>
requires (Extents::rank() == 2)
struct std::formatter<std::mdspan<T, Extents, Layout, Accessor>> {

    std::string_view spec;
    
    constexpr auto parse(format_parse_context& ctx) {
        auto it = ctx.begin();
        auto end = ctx.end();
        spec = std::string_view{it, end};
        return end;
    }
    
    auto format(const std::mdspan<T, Extents, Layout, Accessor>& md, format_context& ctx) const {
        auto out = ctx.out();
        *out++ = '[';
        for (size_t i = 0; i < md.extent(0); ++i) {
            if (i > 0) {
                *out++ = '\n';
                *out++ = ' ';
            }
            *out++ = '[';
            for (size_t j = 0; j < md.extent(1); ++j) {
                if (j > 0)
                    *out++ = ' ';
                if (spec.empty())
                    out = std::format_to(out, "{}", md[i, j]);
                else
                    out = std::format_to(out, "{:" + std::string{spec} + "}", md[i, j]);
            }
            *out++ = ']';
        }
        *out++ = ']';
        
        return out;
    }
};

int main() {
    std::println("{::.2e}", std::mdspan((double []) {1.1111, 2, 3, 4}, 2, 2));
}
c++ string-formatting c++23 mdspan
1个回答
0
投票

过去,对我来说,尽可能多地使用已实现的功能效果最好,尤其是在

std::formatter
方面。避免繁重工作的一种方法是进行以下更改:

  1. 继承
    std::formatter<T>
    以从已实现的
    parse
    功能中受益。
  2. 使用
    std::formatter<T>::format(md[i,j], ctx);
    处理数字格式并推进上下文输出迭代器。

一个工作示例可能如下所示:

#include <print>
#include <mdspan>
#include <format>  

template<class T, class Extents, class Layout, class Accessor>
requires (Extents::rank() == 2)
struct std::formatter<std::mdspan<T, Extents, Layout, Accessor>> : std::formatter<T>
{
    auto format(const std::mdspan<T, Extents, Layout, Accessor> & md, format_context & ctx) const {
        auto out = ctx.out();
        *out++ = '[';
        for (size_t i = 0; i < md.extent(0); ++i) 
        {
            if (i > 0) 
            {
                *out++ = '\n';
                *out++ = ' ';
            }
            *out++ = '[';
            for (size_t j = 0; j < md.extent(1); ++j) 
            {
                if (j > 0)
                {
                    *out++ = ' ';
                }
                std::formatter<T>::format(md[i, j], ctx);
            }
            *out++ = ']';
        }
        *out++ = ']';

        return out;
    }
};

int main() 
{
    auto arr = std::array{ 1.1111, 2.0, 3.0, 4.0 };
    auto span = std::mdspan(arr.data(), 2, 2);
    std::println("{:.2e}", span);
}

此外,如果

parse
,则
ctx.begin()
返回的迭代器应该返回
.begin() == .end()
- 如果不是,那么它应该指向第一个不匹配的字符(如果它是
}
),否则应该抛出
format_error
。您的实现点超出了最后一个字符,并且将/可能导致编译错误。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.