关于您的API
要实际使用代码,您必须编写相当多的代码行才能打印出一行。考虑您的main()
功能:
格式化程序格式;标记流(fm);s(标签::p)<<“Hello World!”<<(标签:;cout<<s.发布_最后_部分();
在这里你需要了解格式化程序
,标记流
和几个标签::*
s、 在构建格式化流之后,您必须调用发布_最后_部分()
获取格式化字符串。考虑一下如何使用标准::format()
:
标准::cout<<std::format(“Hello World!<*{}{}*>**{}**\n”,1,2,“hi!”);
当然,这对段落、跨距、斜体和强调的格式进行了硬编码。理想情况下,你想要的东西与标准::格式
,同时可以选择自定义格式化程序。例如,您可以创建自己的函数,该函数可以解析格式字符串并将渲染委托给另一个函数:
模板<类型名。。。Args>标准::字符串format_markup(FormatterBase&formatter,标准::string_view format_string,参数&…参数){…}整型main(){格式化程序格式{};标准::cout<<format_markup(fm,“Hello World!<*{}{}*>**{}**\n”,1,2,“hi!”);}
当然,您必须想出自己的格式字符串语法。你可以重复使用<
,*
和**
,这样就有了类似markdown的语法。但你可以创建一个HTML格式设置工具
然后将其转换为HTML标记。
您还可以定义自定义格式化程序对于标准::格式
,但自标准::格式
不处理要格式化的东西的嵌套,我认为这不是一种方法。
不要忘记转义包含标记的字符串
考虑写下:
s(标记::p)<<“表达式的结果”<<(s(标签::strong)<<“3*3”)<<“是9。”;
因为有一个*
在您想要增强的文本中,输出将被错误地呈现。因此,您需要在试图标记的字符串中查找标记,并以某种方式转义这些标记字符。
标记流()
应该引用格式设置基数
的第一个参数标记流()
是格式化程序&
,但这会阻止您创建另一个超负荷格式设置基数
并使用它。确保第一个参数的类型为格式设置基数&
.
效率不高
许多内存分配和字符串拷贝都是由您的代码完成的。如果您偶尔渲染标记的文本,这很好,但如果您经常使用它,可能会成为性能瓶颈。理想情况下,您尽可能避免存储数据,但由于嵌套,您仍必须存储中间结果。不过,还是试着标准::移动
字符串。您还可以避免标准::矢量<零件>
:考虑到你只打电话pop_back()
返回格式化的标准::字符串
.
你不必使用操作员<<
虽然我们知道操作员<<
从C++基于流的IO功能,我不确定它们是否适合您正在尝试的操作。它需要您编写大量括号,使使用它的代码更像LISP而不是C++。如果你做了标记流::operator()
接受更多参数?考虑能够写:
使用enum Tag;std::cout<<s(p,“Hello World!”,s(span,s(it,1,2)),“”,s,(em,“hi!”);
所以运算符()
将标记作为第一个参数,然后是任意数量的字符串,在使用格式化程序格式化结果之前,它将连接这些字符串,然后将格式化结果作为标准::字符串
.
考虑进一步分离标记和格式
我在代码中看到的一个问题是s(标记::foo)
它将标记标记与进行格式化的流相结合。如果您可以先构建一个标记字符串,然后将其传递给进行实际格式化的对象,该怎么办?你的代码可能看起来像:
auto-marked_up_text=P(“你好,世界!”,Span(It(1,2)),“”,Em(“嗨!”));格式化程序格式{};标准::cout<<格式标记(fm,标记up_text);
在哪里?P(P)
,跨度
,它
和相对长度单位
现在是存储标记及其参数列表的类,允许格式_标记()
要递归遍历列表,请使用传入的格式设置基数
.