Translation units, linkage, builds, and tests
Declarations, definitions, ODR and executable contracts
A translation unit is one source file after preprocessing its includes. The compiler checks each translation unit; the linker resolves references across their object files. A declaration states an interface, while a definition supplies storage or behavior. Header guards prevent repeated inclusion inside one translation unit; they do not prevent multiple definitions across different translation units.
// config.hpp: declaration
std::string read_name();
// config.cpp: one ordinary out-of-line definition
// std::string read_name() { return "name"; }A non-inline ordinary function defined in a header can violate the one-definition rule when two sources include it. Inline functions may have identical definitions across translation units; template definitions normally need header visibility. static at namespace scope gives internal linkage, creating a separate entity in every translation unit, which may be wrong for shared state. Avoid mutable global state as a shortcut around service ownership.
Compiler diagnostics, linker failures, and runtime test failures identify different boundaries. Compile with warnings to expose narrowing, missing returns, and unused results, but do not treat warning absence as a proof of correctness. A debug sanitizer build can catch invalid memory access and undefined arithmetic on executed paths. Optimized builds can expose bugs hidden by a debug layout; undefined behavior is not a stable behavior to test by exact output.
c++ -std=c++20 -Wall -Wextra -pedantic -pthread main.cpp -o practice
# Optional diagnostic build:
c++ -std=c++20 -g -fsanitize=address,undefined -pthread main.cpp -o practice-debugAn executable specification needs named cases, meaningful assertions, explicit exception types, and a nonzero exit status on failure. A process printing PASS without running assertions is not verification. This lesson's header implementation must remain safe to include in multiple translation units. Its parser demonstrates a narrow input grammar rather than relying on environment variables or filesystem state. Tests are deterministic and isolate each fresh configuration load.
Put it into practice
Implement the exercise in a full-screen workspace, then run its tests.