首页 > 解决方案 > 关于打印 STL 容器以进行认可测试的公约

问题描述

我正在使用优秀的ApprovalTests.cpp库编写批准测试。该库自动生成函数结果的“快照”。T使用ostream& operator<< (T val). _

此运算符一直是用于将某些值格式化为文本表示的 C++ 约定。虽然原始类型支持此运算符并且您可以为自定义类型编写自己的实现,但对于 STL 容器(如std::vector.

您可以实现自己的,甚至使用其他库,如fmtor pprint。以下是一些具有类似输出的示例。我使用泛型类型STREAM作为参数,而不是ApprovalTests.cpp 推荐ostream的具体类型,但这个想法没有改变。

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

https://github.com/fmtlib/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标题:

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 容器都这样做很乏味。这样做可能会破坏其他代码,例如,相同的运算符已为向量重载。

在 Rust 中,您只需将#[Debug]struct格式化的文本添加到文本中,它就可以自动转换为文本表示形式,或者如果您需要一些非规范表示形式,您可以自己实现特征。结构作者有责任定义其Debug实现。这就是为什么 Rust 标准库中的每个容器都有自己的Debug实现。

我在问 C++ 中是否存在一些约定,或者有一些类似的标准提案。它可能对批准测试很有用,比如在我的例子中,但也适用于日志记录或调试(调试器可以使用此格式化程序向用户显示变量值)。

标签: c++fmtapproval-tests

解决方案


我不知道打印容器的任何约定或标准建议。但是,{fmt} 库可以打印任何范围和元组之类的内容:https ://fmt.dev/latest/api.html#ranges-and-tuple-formatting因此您可以将其与 ApprovalTests 集成并避免定义 ostream 插入运营商自己。

免责声明:我是 {fmt} 的作者。


推荐阅读