Note
These rules evolve. Existing code may violate them. If you update style, please do it in a separate commit named "Cleanup: code style" so reviews stay chill. 🙏🧼
| 🧩 Thing | ✅ Style | 🧪 Example |
|---|---|---|
| Top-level namespaces | lowercase | mdl, render |
| Class names | CamelCase | MyUsefulClass |
| Functions, methods, vars, params | camelCase | void myUsefulFunction(const int aHelpfulParameter); |
| Private members | m_ prefix |
m_value |
| Constants | UpperCamelCase | static const int ThisIsAConstant = 1; |
- 🧰 We use
clang-formatwith rules in.clang-format. - ✅ Formatting is enforced by CI.
- 🔗 Grab the correct
clang-formatbinaries from the dev-tools repo: https://github.com/TrenchBroom/dev-tools
- 🧹 We use
clang-tidywith rules in.clang-tidy(enforced by CI). - 🧱 Avoid header files that declare more than one class.
- 🧭 Class members are usually ordered as follows (ok to deviate with a good reason):
- Type aliases and static const members
- Member variables
- Constructors / destructors
- Operators
- Public member functions
- Protected member functions
- Private member functions
- Extension interface (private pure virtual member functions)
- ⚡ We follow "almost always auto" and use
autounless it gets awkward. - 🧷 Use
auto*when declaring a pointer variable (e.g.auto* entityNode = new EntityNode{...}). - 🧊 Use
constwherever possible. - 🧭 Prefer left-to-right declarations:
auto entity = Entity{...};instead ofEntity entity{...}. - 🕶️ Use private namespaces for implementation details in cpp files. Prefer free functions in an anonymous namespace over private helper methods when possible.
- 🧪 Prefer
std::optionalover magic constants likeNaNto signal absence. - 🧩 Prefer
std::variantover inheritance. - 🧱 Prefer
structoverclassfor simple POD-like types. - 🧳 Prefer value semantics.
- 🧠 We use C++20.
- ✅ The entire source code and test cases must compile without warnings.
- 🧊 Everything that can be const should be const (methods, parameters, variables).
- 🏃 Move semantics should be used if possible. Prefer passing objects by value if a function takes ownership.
- 🧰 Use RAII where possible.
- 🪢 Avoid raw pointers unless confined to a method, class, or subsystem.
- 🧷 Do not return raw pointers from public methods. Favor references and smart pointers.
- 🚫 Do not use exceptions. Use
ResultandErrorinstead.
This section presents some guidelines to keep compilation times low.
Avoid including headers in other headers. Remember that including header B in header A includes B in every file that includes A, and so on.
- 🔭 Use forward declarations wherever possible (classes, class templates, scoped enums, type aliases, template aliases).
- 🧩 Use a forward declaration unless:
- It is a type defined in namespace
std. - The type is used by value in a member variable declaration or a function declaration.
- The type is used in the implementation of a template function.
- It is a type defined in namespace
- 🧺 Use forward declarations for types used as standard library container parameters. If you declare
std::vector<Foo>in a class, you can forward-declareFooin the header and define the destructor in the cpp file whereFoois complete.