ZeroErr
载入中...
搜索中...
未找到
Printer MultiFunctor

Printer 是一个有状态的模板打印类,默认使用内部 StringBuffer 保存文本,也可连接调用方显式提供的输出流。标准流适配需显式启用,参见头文件依赖约定。

按能力匹配与头文件依赖

打印器通过类型提供的操作选择规则,不要求类型必须是某种 STL 模板:

  • 容器提供 const begin()/end() 和可复制、可递增的迭代器;支持下标的容器使用方括号。
  • 映射元素提供 first/second;复数提供返回算术值的 real()/imag()。
  • 文本提供 traits_type::char_type = char、data()/size(),或可转换为 const char*。普通字符容器仍按容器打印。
  • 指针包装提供可转换为 const void* 的 get();弱引用提供返回这类包装的 lock()。
  • tuple 协议提供 std::tuple_size<T> 和可通过 ADL 找到的 get<I>(const T&)。容器优先于 tuple 规则。

调用方自行包含 <tuple>、<complex>、<memory> 等类型定义;放在 zeroerr/print.h 之前或之后都可以,只需在打印调用前定义完整。打印不会复制对象或取得智能指针的所有权。

打印头仍保留现有 std::ostream 和 std::string 接口。stringstream 管理及类型名 demangle 的实现位于 .cpp:使用时链接 zeroerr 库,或在单头文件模式中于一个翻译单元定义 ZEROERR_IMPLEMENTATION。

构造函数

可以选择将文本保存在内部缓冲区,或者连接调用方提供的流。str() 返回内部 zeroerr::String。

Printer(); // capture into StringBuffer
template<class Stream> explicit Printer(Stream& os); // attach caller's stream

如果想快速获得一个能打印到标准输出流的对象,可以调用如下方法:

extern Printer& getStdoutPrinter();
extern Printer& getStderrPrinter();

打印任意类型

仿函数 print(...) 可以传入任意个任意不同类型的参数,他们将被依次打印。

Example:

int main() {
auto print = zeroerr::getStderrPrinter();
int a = 1;
int& b = a;
int* c = &a;
print(a, b, c);
return 0;
}
Printer & getStderrPrinter()
定义 print.cpp:14
int main(int argc, const char **argv)
定义 unittest.cpp:1263

Output:

1 1 <int* at 0x7ffebc813ed4>

函数指针输出为 <函数指针类型 at 地址>,空函数指针输出为 nullptr。 std::function 输出为 <包装类型 holding 目标类型>,为空时输出 nullptr。 打印不会调用目标函数,也支持容器和元组中的这些类型。

同时支持 STL container:

int main() {
auto print = zeroerr::getStderrPrinter();
std::vector<int> vec = {1, 5, 2};
auto get_student = [](int id) {
if (id == 0) return std::make_tuple(3.8, 'A', "Lisa Simpson");
if (id == 1) return std::make_tuple(2.9, 'C', "Milhouse Van Houten");
if (id == 2) return std::make_tuple(1.7, 'D', "Ralph Wiggum");
throw std::invalid_argument("id");
};
print(a, b, c);
print({get_student(0), get_student(1), get_student(2)});
return 0;
}

Output:

[1, 5, 2]
{
(3.8, A, Lisa Simpson)
(2.9, C, Milhouse Van Houten)
(1.7, D, Ralph Wiggum)
}

也可以方便的打印智能指针:

std::shared_ptr<int> p(new int(42));
print(p);
std::unique_ptr<int> up(new int(42));
print(std::move(up));

Output:

<std::shared_ptr<int> at 0x555e1f936140>
<std::unique_ptr<int, std::default_delete<int> > at 0x555e1f931100>

不同类型的优先级规则

该函数在打印不同类型元素时,是根据不同的类型,选取不同的优先级规则,例如,一个 string 类型,是container类型,也是Object类型,但因为std::string 有专属的规则在level4, 所以会调用专属规则进行打印。

level types
5 User Customized Rules
4 std::string, std::complex, std::map
3 std::share_ptr, std::unique_ptr, std::weak_ptr, std::tuple, Array
2 container(who has begin, end methods), streamable types(with << operator), bool
1 char, wchar, POD type(need PFR library)
0 Object, C pointer, integer, float

配置参数

这个仿函数可以被配置多种不同的运行模式:

  1. 紧凑模式 - 所有元素不换行,单行打印,如 {"a" : 1, "b" : 2}
    print.isCompact = true;
  2. 彩色输出模式
    print.isColorful = true;
  3. 引用模式,如果启用时字符串会加引号, "a"
    print.isQuoted = true;
  4. 缩进 - 默认是 2.
    print.indent = 4
  5. 换行符,windows下您可以调整 - 默认是 \n.
    print.line_break = "\r\n"; // for windows

在流输出中打印

Printer print; // capture into StringBuffer
std::cerr << print("hello world") << std::endl;

自定义规则

打印规则是可以自定义的,并且会在最高优先级上。创建一个 PrinterExt function templates:

template <typename T> typename std::enable_if< <condition>, void>::type
zeroerr::PrinterExt(Printer& P, <type of Input>, unsigned level, const char* lb, rank<N>);
void PrinterExt(Printer &, const T &, unsigned, const char *, rank< 0 >)
PrinterExt is an extension of Printer that allows user to write custom rules for printing.
定义 print.h:388

如下是一个LLVM中指针元素的打印规则,支持 llvm::Value, llvm::Type 以及当前要打印的具体类型 llvm::Function:

namespace zeroerr{
// This will create a special rule for printing pointers from LLVM value
template <typename T>
typename std::enable_if<
std::is_base_of<llvm::Value, T>::value || std::is_base_of<llvm::Type, T>::value, void>::type
PrinterExt(Printer& P, T* s, unsigned level, const char* lb, rank<1>) {
if (s == nullptr) {
P.os << P.tab(level) << "nullptr" << lb;
} else {
std::string text; // explicitly include <string> and LLVM raw_ostream headers
llvm::raw_string_ostream os(text);
s->print(os);
os.flush();
P.os << text;
}
}
// Even though llvm::Function is a subclass of `llvm::Value`, but this rule is in rank 2.
// So it will cover the basic rule. All the pointer base of `llvm::Function` will call
// this function to print.
template <typename T>
typename std::enable_if<std::is_base_of<llvm::Function, T>::value, void>::type PrinterExt(
Printer& P, T* s, unsigned level, const char* lb, rank<2>) {
if (s == nullptr) {
P.os << P.tab(level) << "nullptr" << lb;
} else {
std::string text; // explicitly include <string> and LLVM raw_ostream headers
llvm::raw_string_ostream os(text);
P.os << P.tab(level) << "Function " << FgCyan;
os << *s;
os.flush();
P.os << text << Reset;
}
}
} // namespace zeroerr
定义 assert_text.cpp:5
const char * FgCyan
定义 color.cpp:48
const char * Reset
定义 color.cpp:34
A functor class Printer for printing a value of any type.
定义 print.h:87
rank is a helper class for Printer to define the priority of overloaded functions.
定义 typetraits.h:43