增强现有匹配器系统
作者: mitchgrout创建于 2025年10月27日更新于 2026年7月13日
考虑以下代码片段:
struct event { std::string message; std::any data; };
auto events = std::vector<event> { ... };
auto found = std::find_if(events.begin(), events.end(), [](auto event) { return event.message == "task started"; });
CHECK(found);虽然这样做可以解决问题,但我仍然有几个疑虑:
- 我们需要使用
<algorithm>来实现std::find_if,这会增加不小的包含成本(参见 [artificial-mind.net/projects/compile-health/](https://artificial-mind.net/projects/compile-health/))。 auto found = ...表达式的大部分部分是迭代性的代码片段。- 如果断言失败,我们无法了解
events的内容(假设对于event和std::vector都可以提供字符串化功能)。- 当在 CI/CD 上发生失败时,这种情况尤其令人恼火,因为调试并不容易获得。
- 这可以通过明确的
CAPTURE(events)来解决,但这感觉像是一个附加的解决方案。 从 RSpec 中获得灵感,我们可以将其重写为以下假设形式:
using namespace doctest::matchers;
CHECK(events == Includes( Splat("task started", ignore) ));Includes 接收一个 matcher<T> 对象,基本上执行 std::find_if 操作。另一方面,Splat 接收一个 Args... 序列,这些是 T 的成员,将 T 对象拆分为其部分,然后逐个比较每个部分(请注意,这只在 T 是 POD 的情况下有效),实际上执行与 std::find_if 关联的 lambda。doctest::ignore 是一个特殊的匹配器,总是为真。这将解决前三个问题:
- 它直接可用于
doctest,包含和编译成本应该很低。 - 断言现在几乎完全由相关组件组成。
- 如果断言失败,表达式分解器将请求显示
events,在调试时提供更多上下文。
内容来源: doctest/doctest