欢迎光临散文网 会员登陆 & 注册

pprint 源码阅读

2022-09-10 22:39 作者:Meriex  | 我要投稿

上一次一起学习完 TinyFormat 的源码后我们收获很多,那这一次我们同样来看一个用于格式化输出的库 pprint ,也同样是一个  header only 的库。

首先我们同样看一下 pprint 的基础用法(来自 README.md ):

可以看到用法上和 TinyFormat 有一定区别,使用上更贴近 sd::cout<< 而不是 ::printf

那么就让我们正式开始吧,首先看一下 PrettyPrinter 的构造方式:

可以看到 PrettyPrinter 接收一个 ostream& 类型的参数用于指明输出的目的流,默认是 std::cout ,另外还设置了行结尾 line_terminator_indent_ 缩进,以及 quotes_ 是否在输出字符串是加上 " 包裹, compact_ 这里指的应该是紧凑输出。

紧接着来分析一下 PrettyPrinter::print 函数的实现:

可以看到 print 做了三个重载,第一个是直接调用 print_internal 。第二个接收 std::initializer_list<T> 类型的参数也同样调用 print_internal ,这里为什么要单独调一下原因我们暂时不知道,可以后面再看一下,至于 std::initializer_list 如果大家不清楚的话这里简单说明一下,用大括号 {} 做初始化时实际上就是通过这个类型实现的。

接着是一个接受变长模板参数的重载,首先打印第一个 value ,接着打印分隔符空格,接着递归调用 print 打印剩下的参数。

这里实际上我们知道 print 的实现可以通过折叠表达式优化一下:

怎么样,是不是看上去好多了,唯一的问题就是对于 std::initializer_list 类型的参数我们后续可能还需要特殊处理,那现在先来看一下 print_internal 的实现:

emmm, 我也是惊了,上面我列出的只是一小部分,作者惊人的为每一个内置类型做了单独适配,尤其后面这一大堆类型判断让我属实有点绷不住啊,结合后面的一个给 vector 的一版重载:

还是先简单分析一下这里的用法:

这里 enable_if 的作用是判断 Container 的类型是否为 std::vector ,如果不是那么禁用模板,如果是那么通过 ::type 拓展模板实例的返回类型为 void ,当然 enable_if 只是判断表达式结果为 true_type 还是 false_type ,实际判断是由 is_specialization 实现的:

这是一个比较常见但是经典的实现,由 @Databyte 提出,这里通过特化使得忽略模板参数后类型一致的两个参数可以匹配到特化版本,其 ::typestd::true_type ,否则匹配到非特化版本,其 ::typestd::false_type

这里举个简单的例子 is_specialization<std::vector<int>, std::vector> ,那么此时我们就可以看到 Ref 的类型为 std::vector 是可以匹配的上的;而对于 is_specialization<std::list<int>, std::vector> 来说就没法匹配特化版本,只能匹配非特化版本此时 Teststd::list<int>Refstd::vector

回到 pprint ,那实际上像这样去实现 print_internal 也就是对每一个可能的情况进行处理是非常不推荐的,更不用说这里用了 enable_if 的方式去禁用模板函数,这样一来一旦 STL 中新增了类型那么除了新增特定的处理外还需要改动上面的 print_internal 声明否则就会导致编译器找到多个函数,至少也应该用特化去实现。

后续的代码那基本也都是一个套路,我们就不继续往下细看了。

下次再会!


pprint 源码阅读的评论 (共 条)

分享到微博请遵守国家法律