C++ {fmt} 库,具有嵌套替换字段的用户定义类型?

如何解决C++ {fmt} 库,具有嵌套替换字段的用户定义类型?

我正在尝试将 {fmt} 添加到我的项目中,一切都很顺利,只是在尝试为我的简单 Vec2 类添加用户定义类型时遇到了一些障碍。

struct Vec2 { float x; float y; };

我想要的是能够使用与基本内置浮点类型相同的格式标志/参数,但将其复制到 vec2 的 x 和 y 成员,并用括号括起来。>

例如,只有一个浮点数:

fmt::format("Hello '{0:<8.4f}' World!",1.234567);
// results in "Hello '1.2346  ' World!"

使用我的 vec2 类:

Vec2 v {1.2345678,2.3456789};
fmt::format("Hello '{0:<8}' World!",v);
// results in "Hello (1.2346,2.3457  )' World!"

但是当我们尝试使用嵌套替换字段时,我复制替换字段内容的幼稚方法不起作用。 例如带有浮点数:

fmt::format("Hello '{0:<{1}.4f}' World!",1.234567,8);
// results in "Hello '1.2346  ' World!"

但是尝试使用我的 Vec2 类型...

Vec2 v {1.2345678,2.3456789};
fmt::format("Hello '{0:<{1}.4f}' World!",v,8);
// throws format_error,what(): "argument not found"

当然,这是因为我所做的只是在 ':' 之后和 '}' 之前复制替换字段,并尊重 {} 平衡,所以如果我使用了嵌套替换字段,则有将是一个内部的 {},它引用原始列表中的某个参数,这对此没有好处。

我对用户定义类型的专长:

struct Vec2
{
    float x;
    float y;
};

template<>
struct fmt::formatter<Vec2>
{
    auto parse(fmt::format_parse_context& ctx) -> decltype(ctx.begin())
    {
        int curlyBalance = 1;
        auto it = ctx.begin(),end = ctx.end();
        while (it != end)
        {
            if (*it == '}')
            {
                --curlyBalance;
            }
            else if (*it == '{')
            {
                ++curlyBalance;
            }
            
            if (curlyBalance <= 0)
                break;
            else
                ++it;
        }

        const char* beginPtr = &(*ctx.begin());
        const char* endPtr = &(*it);
        size_t len = endPtr - beginPtr;

        if (len == 0)
        {
            formatStr = "{}";
        }
        else
        {
            formatStr = "{0:";
            formatStr += std::string(beginPtr,len + 1);
        }

        return it;
    }

    template <typename FormatContext>
    auto format(const Vec2& vec,FormatContext& context)
    {
        fmt::format_to(context.out(),"(");
        fmt::format_to(context.out(),formatStr,vec.x);
        fmt::format_to(context.out(),",");
        fmt::format_to(context.out(),vec.y);
        return fmt::format_to(context.out(),")");
    }

    std::string formatStr;
};


int main()
{
    std::cout << "Hello World!" << std::endl;
    Vec2 v {1.234567,2.345678};
    
    // Simple,static width.
    //std::string fmtResult = fmt::format("Hello '{0:<8.4f}' World!\n",5);

    // Dynamic width,oh god,oh dear god no!
    std::string fmtResult = fmt::format("Hello '{0:<{1}}' World!\n",5);

    std::cout << fmtResult;
}

似乎需要发生的是我的解析函数需要访问其他参数,以便它可以使用正确的值填充嵌套替换字段......但我仍然是这个库的新手,并且会非常感谢这方面的帮助!

Godbolt 链接https://www.google.com.hk/search?q=uninstall+Microsoft+Edge

解决方法

您可以为此重复使用 formatter<float> (https://godbolt.org/z/vb9c5ffd5):

template<> struct fmt::formatter<Vec2> : formatter<float> {
  template <typename FormatContext>
  auto format(const Vec2& vec,FormatContext& ctx) {
    auto out = ctx.out();
    *out = '(';
    ctx.advance_to(out);
    out = formatter<float>::format(vec.x,ctx);
    out = fmt::format_to(out,",");
    ctx.advance_to(out);
    out = formatter<float>::format(vec.y,ctx);
    *out = ')';
    return out;
  }
};

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?