The main goal of the coding rules is code consistency (i.e. regardless of who writes the code).
To achieve this, the rules should be written so that it minimizes the number of ways to write the code.
However, these rules are not absolute. Exceptions can be made if justified.
Many of the rules below are enforced or assisted by the tooling files in this repository: .clang-format, .clang-tidy and compile_flags.txt.
Coding rules
Rules that describe the way to implement.
- General
- Friendship: only when declaring operators (i.e.
<,==,<<, ...) - Shared pointers: only for instances of interfaces
- Dynamic allocation: do not use (i.e. no use of
new) - Exceptions: do not use
- Cast: if possible, use
static_cast, elsereinterpret_cast. Do not usedynamic_castorC style cast - Comments: for everything
- Asserts: for all implicit conditions required for correct execution
- Aliases: use the
usingkeyword instead of thetypedefkeyword - Lambda: use
std::functionas the type but declare it with alambda function(or even better, declared with custom conceptCallable) - Inheritance: do not use inheritance except for interfaces. Prefer composition over inheritance
- Dead code: do not use (no what-if code)
- Files: only one class per file, except for header-only libraries
- Libraries:
- Implementation: should expose only the public interface (i.e. may require PIMPL pattern)
- Publication: should be published as a header-only library whose implementation is in
#ifdef IMPLEMENTATIONsection
- Friendship: only when declaring operators (i.e.
- Headers
- Header inclusion: no forward declaration
- Header guard:
#pragma once- Declaration order
- Accessibility order:
- public
- protected
- private
- Categories order:
- Sub-classes
- Static methods
- Static members
- Non-static methods
- Non-static members
- Accessibility order:
- Declaration order
- Sources
- Definition order: same order as declared
- Include order
In alphabetical order for each category:
- Corresponding header
- Standard library headers
- External dependencies headers
- Project headers
- Include order
In alphabetical order for each category:
- Definition order: same order as declared
- Variables
- Declaration
- Instruction: only one declaration per line. This rule also applies for class members
- Initialization: if possible, initialize variable on declaration. This rule also applies for class members
- Scope: declare the variable inside a method, a class, or a namespace
- Pointer/Reference: use references instead of pointers when the value is not optional, unless the object is contained in a data structure
- Constness: maximize the constness of variables
- Primitive type: use only strong primitive types (ex:
uint32_t,size_t) - Type: use the most accurate types (ex:
istringstreaminstead ofstringstream) autokeyword: use only for lambda, loop-variable and types that are longer than 15 characters
- Declaration
- Functions
- Inline functions: only for template specialization
- Inline methods: only for setters and getters
- Side effect: avoid side effect functions
Exception valid for: data structures, in-out parameters, multiple outputs returninstruction: immediately exit a function when a required condition is not fulfilled- Parameters
- Default value: allowed, rule TBD
- Passing: pass primitive types by value, pass any other types by reference
- Global scope functions: do not use, functions should be placed within a namespace or a class
- Structs
- Usage: use structs for mainly public attributes and methods
Other rules inClasses
- Usage: use structs for mainly public attributes and methods
- Classes
- Constructor: do not use implicit conversions, use the
explicitkeyword - Virtual: declare the destructor as a virtual for classes that contain virtual methods
- Concept: prefer concepts over interfaces
- Interface:
- Usage: use interfaces when polymorphism is required within a collection (like array, set, map, ...)
- Implementation: should be implemented as a class with only virtual methods
- Sub-classes: only for PIMPL pattern
- Accessibility: minimize the accessibility of the class members
- Constness: maximize the constness of the member functions
- Static: only for utility functions with private implementation, use namespaces if no private implementation
- Singleton: forbidden, rule TBD
- Constructor: do not use implicit conversions, use the
- Namespaces
- Usage: use namespaces for utility functions, for libraries, for converters of enumerators, and for enumerators as flag
usinginstruction:using namespaceinstruction should be avoided or used in a function scope or namespace scope (not in global scope)
- Enumerators
- Declaration: should be declared with
enum classexcept for flags where it should be declared withnamespace E<enum_name> { enum Type { ... } } - Flags: all values should be defined with
1 << N, whereNis the index of the value - Converters: all functions should be defined in the namespace corresponding to the enumerator as
static constexprfunctions withswitch casestatements
- Declaration: should be declared with
- Unions: use variants instead of unions
- Macros:
- Usage: use macros when using
__FUNCTION__or__LINE__ - Implementation:
- public macros should be surrounded by
do { ... } while (0) - macros with parentheses should be called with
;(i.e. no;at the end of the macro)
- public macros should be surrounded by
- Usage: use macros when using
Naming rules
Rules that describe the way to name.
- General
- Language: English only
- Word
number: do not usenumber. Usecount,idorindex(ex: carId instead of carNumber) - Plural: no plural, describe as a container (ex: carList instead of cars)
- File name: same as declared/defined class, PascalCase for class, PascalCase without leading
Efor enumerator, snake_case for namespace - Folder name: denomination of the content as PascalCase for classes and snake_case for namespaces
- Headers
- Extension:
.honly if c compatible, else.hpp - Content: only declarations and inline functions and template functions
- Extension:
- Sources
- Extension:
.cpp
- Extension:
- Variables
- Iteration index:
i, j, k...are reserved name for iteration index - Case: camelCase
- Naming: same name as type in camelCase (ex: FileWatcher fileWatcher)
- Boolean: boolean variables must start with
b,isorhas - Container: container variables must end with the type of the container (ex: std::map<string, int> nameAgeMap)
- Modifiers (as class member)
- Private/Protected/Public: do not use any marker
- Constant: SCREAMING_SNAKE_CASE
- Static: do not use any marker
- Iteration index:
- Functions
- Overloading: function names must be unique, except for templated functions
- Case: camelCase
- Boolean: boolean functions must start with
b,isorhas - Modifiers (as method member)
- Private/Protected/Public: do not use any marker
- Static: do not use any marker
- Enumerators
- Case: PascalCase with leading
EIf enum is a flag, use namespace E<enum_name> { enum Type { ... } } - Enum values case: PascalCase
- Namespace: same name as enum without leading
E
- Case: PascalCase with leading
- Classes
- Naming
- Modifiers
- Interface (only virtual pure methods): PascalCase with leading
Iand trailingable(ex: IPlayable) - Abstract: PascalCase with leading
A - Static (only static methods): do not use any marker
- Templated: do not use any marker
- Interface (only virtual pure methods): PascalCase with leading
- Order:
- Data involved (ex: Car, Shoe, Key) (still no plural)
- Data processing method (ex: Watcher, Cleaner, Filter)
- Extension: the child class name must end with its parent class name
Abbreviate the parent name if its length is greater than15
Add a comment just above the parent class to define the used abbreviation Other rules inTypes
- Modifiers
- Naming
- Methods
- Case: camelCase. Should start with
getonly if no computation is involved, should return a reference or a pointer.
- Case: camelCase. Should start with
- Concepts
- Case: PascalCase with trailing
able
- Case: PascalCase with trailing
- Namespaces
- Case: snake_case
- Types
- Case: PascalCase
- Macros
- Case: SCREAMING_SNAKE_CASE with leading
P_for private macros
- Case: SCREAMING_SNAKE_CASE with leading
Format rules
All of the format rules to apply are defined in the clang-format file.
MIT License. See LICENSE file. Please refer me with:
Copyright (c) Nicolas VENTER All rights reserved.