Comparison Story: CppTextFinder

6.  Conclusion — sample output, build, and references

6.  Conclusion

The four parts come together in a small executable: three library modules that know nothing about each other and one main.cpp that imports all three and glues them together with two lambda callbacks. What follows is a look at that executable in action.

6.1  Sample Output

Matching files are grouped under their containing directory. The summary line reports how many files were visited (extension-matched) and how many matched the regex.
$ text_finder /P .. /p .cpp,.ixx /r "std::regex"

  ../CppTextFinder/Output/src
      Output.ixx

  ../CppTextFinder/EntryPoint/src
      main.cpp

42 file(s) visited, 2 file(s) matched
Directories that contain no matching files are hidden by default (/H true). Set /H false to print every directory as it is entered — useful for confirming which subtrees the walker actually visits and which ones the built-in skip list rejects:
$ text_finder /P . /p .cpp /r "ZZZNOMATCH" /H false

  .
  ./CommandLine
  ./CommandLine/src
  ./DirNav
  ./DirNav/src
  ./EntryPoint
  ./EntryPoint/src
  ./Output
  ./Output/src

42 file(s) visited, 0 file(s) matched
Verbose mode (/v) echoes every resolved option before traversal — handy when you want to see exactly which defaults the parser applied:
$ text_finder /P . /p .cpp /r "int main" /v

Options:
  /P  .
  /r  int main
  /s  true
  /H  true
  /p  .cpp

  ./EntryPoint/src
      main.cpp

42 file(s) visited, 1 file(s) matched

6.2  Building & Running

C++23 named modules require CMake 3.28 or later. On Windows use Visual Studio 2022 (MSVC 19.41+); on Linux/macOS use Clang 17+ or GCC 14+ with Ninja.
# Windows / Visual Studio 2022
cmake -S . -B build -G "Visual Studio 17 2022" -A x64
cmake --build build --config Release

# executable lands at build/EntryPoint/Release/text_finder.exe
# Linux / macOS with Ninja
cmake -S . -B build -G Ninja
cmake --build build

# executable lands at build/EntryPoint/text_finder

6.3  Testing

Each library part provides a src/test.cpp file containing hand-written unit tests. Tests are compiled into a stand-alone executable by the part's own CMakeLists.txt and registered with CTest via add_test() — no external test framework is required.
# Run all tests
ctest --test-dir build --output-on-failure

# Run one part's tests in isolation
ctest --test-dir build -R cmd_line_tests --output-on-failure
ctest --test-dir build -R dir_nav_tests  --output-on-failure
ctest --test-dir build -R output_tests   --output-on-failure

6.4  Design Takeaways

  • C++23 modules replace headers cleanly. Each library is a single .ixx file that both declares and defines its public API. EntryPoint's import cmd_line; gives it exactly the exported symbols and nothing more — no macro pollution, no include-order fragility.
  • std::function is the callback contract. Where Rust uses a trait, C++ uses two std::function members initialised by lambdas captured on &out. This trades a small runtime cost per call for freedom in how the application supplies its hooks.
  • std::regex is slower than the alternative engines. A backtracking NFA rescans input on each match attempt; Rust's regex and Python's re both use DFA-based engines that scan in one linear pass. On the comparison workload (see Project Story: TextFinder — Performance) the C++ variant is roughly the same speed as the optimized Rust variant, and slower than the Python variant that's mostly C under the hood.
  • Lazy directory printing avoids a two-pass walk. Output::on_dir defers the header until the first match arrives; the walker fires on_dir unconditionally on every directory and the output layer decides whether to actually emit anything. This keeps DirNav simple and pushes the policy decision into Output.
  • Non-throwing filesystem calls. Every std::filesystem call in DirNav takes an std::error_code. Permission-denied subdirectories silently drop out; the walk continues. This matches the "traverse what you can" behavior of the Rust variant without wrapping every call in a try.

6.5  References

ResourceDescription
1. Introduction Overview, parts, CLI options, and the design roadmap for the rest of this thread.
2. CommandLine CmdLine — argv into unordered_map + patterns.
3. DirNav Callback-driven DirNav depth-first walker.
4. Output Output — regex match + grouped stdout emission.
5. EntryPoint main.cpp — imports, callback wiring, and startup flow.
Rust Comparison thread Parallel walkthrough of the optimized Rust implementation.
Project Story: TextFinder Cross-language overview of all four TextFinder implementations, CLI, performance, and the optimization summary.
CppTextFinder repository Source of all four parts discussed in this thread.