印刷STL容器用于认可测试的约定
Convention on printing STL containers for approval tests
我正在使用出色的 ApprovalTests.cpp 库编写批准测试。该库自动从函数生成 "snapshots" 结果。快照是使用 ostream& operator<< (T val)
.
将 T
类型的结果序列化到文件中生成的
此运算符一直是将某些值格式化为文本表示形式的 C++ 约定。虽然原始类型支持此运算符,并且您可以为自定义类型编写自己的实现,但对于像 std::vector
.
这样的 STL 容器,没有标准的实现
您可以自己实现,甚至可以使用 fmt
或 pprint
等其他库。下面是一些具有类似输出的示例。我使用通用类型 STREAM
作为参数而不是具体类型 ostream
作为 recommended by ApprovalTests.cpp 但想法没有改变。
for循环
template <typename STREAM, typename T> STREAM& operator<<(STREAM& os, const std::vector<T>& vec) {
os << "[";
for (const auto& x : vec) {
os << x << ", ";
}
os << "]";
return os;
}
ostream_iterator
template <typename T> std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
using namespace std;
os << "[";
copy(v.begin(), v.end(), ostream_iterator<T>(os, ", "));
os << "]";
return os;
}
fmt
template <typename STREAM, typename T> STREAM& operator<<(STREAM& os, const std::vector<T>& vec) {
fmt::print(os, "[{}]", fmt::join(vec, ", "));
return os;
}
与<fmt/ranges.h
header:
template <typename STREAM, typename T> STREAM& operator<<(STREAM& os, const std::vector<T>& vec) {
fmt::print(os, "{}", vec);
return os;
}
印刷精美
https://github.com/p-ranav/pprint
template <typename STREAM, typename T> STREAM& operator<<(STREAM& os, const std::vector<T>& vec) {
pprint::PrettyPrinter printer{os};
printer.print(vec);
return os;
}
cxx-prettyprint
只需包含 prettyprint.hpp,它适用于 STL 容器。
这似乎是最简单的解决方案,但与其他解决方案存在相同的问题,可能会破坏其他代码。
约定?
在使用了一些 Rust 之后,我发现为每个 C++ STL 容器执行此操作很乏味。这样做可能会破坏其他代码,例如,相同的运算符已为 vector 重载。
在 Rust 中,您可以在要格式化为文本的 struct
上添加 #[Debug]
,它可以自动转换为文本表示,或者如果您需要一些 non-canonical表示。结构作者有责任定义其 Debug
实现。这就是为什么 Rust 标准库中的每个容器都有自己的 Debug
实现。
我想问的是 C++ 中是否存在某些约定,或者是否有一些类似的标准提案。它可能对批准测试很有用,就像在我的例子中一样,但对日志记录或调试也很有用(调试器可以使用此格式化程序向用户显示变量值)。
我不知道关于打印容器的任何约定或标准提案。然而 {fmt} library can print anything range- and tuple-like: https://fmt.dev/latest/api.html#ranges-and-tuple-formatting 所以你可以将它与 ApprovalTests 集成并避免自己定义 ostream 插入运算符。
免责声明:我是{fmt}的作者。
我正在使用出色的 ApprovalTests.cpp 库编写批准测试。该库自动从函数生成 "snapshots" 结果。快照是使用 ostream& operator<< (T val)
.
T
类型的结果序列化到文件中生成的
此运算符一直是将某些值格式化为文本表示形式的 C++ 约定。虽然原始类型支持此运算符,并且您可以为自定义类型编写自己的实现,但对于像 std::vector
.
您可以自己实现,甚至可以使用 fmt
或 pprint
等其他库。下面是一些具有类似输出的示例。我使用通用类型 STREAM
作为参数而不是具体类型 ostream
作为 recommended by ApprovalTests.cpp 但想法没有改变。
for循环
template <typename STREAM, typename T> STREAM& operator<<(STREAM& os, const std::vector<T>& vec) {
os << "[";
for (const auto& x : vec) {
os << x << ", ";
}
os << "]";
return os;
}
ostream_iterator
template <typename T> std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
using namespace std;
os << "[";
copy(v.begin(), v.end(), ostream_iterator<T>(os, ", "));
os << "]";
return os;
}
fmt
template <typename STREAM, typename T> STREAM& operator<<(STREAM& os, const std::vector<T>& vec) {
fmt::print(os, "[{}]", fmt::join(vec, ", "));
return os;
}
与<fmt/ranges.h
header:
template <typename STREAM, typename T> STREAM& operator<<(STREAM& os, const std::vector<T>& vec) {
fmt::print(os, "{}", vec);
return os;
}
印刷精美
https://github.com/p-ranav/pprint
template <typename STREAM, typename T> STREAM& operator<<(STREAM& os, const std::vector<T>& vec) {
pprint::PrettyPrinter printer{os};
printer.print(vec);
return os;
}
cxx-prettyprint
只需包含 prettyprint.hpp,它适用于 STL 容器。
这似乎是最简单的解决方案,但与其他解决方案存在相同的问题,可能会破坏其他代码。
约定?
在使用了一些 Rust 之后,我发现为每个 C++ STL 容器执行此操作很乏味。这样做可能会破坏其他代码,例如,相同的运算符已为 vector 重载。
在 Rust 中,您可以在要格式化为文本的 struct
上添加 #[Debug]
,它可以自动转换为文本表示,或者如果您需要一些 non-canonical表示。结构作者有责任定义其 Debug
实现。这就是为什么 Rust 标准库中的每个容器都有自己的 Debug
实现。
我想问的是 C++ 中是否存在某些约定,或者是否有一些类似的标准提案。它可能对批准测试很有用,就像在我的例子中一样,但对日志记录或调试也很有用(调试器可以使用此格式化程序向用户显示变量值)。
我不知道关于打印容器的任何约定或标准提案。然而 {fmt} library can print anything range- and tuple-like: https://fmt.dev/latest/api.html#ranges-and-tuple-formatting 所以你可以将它与 ApprovalTests 集成并避免自己定义 ostream 插入运算符。
免责声明:我是{fmt}的作者。