This file describes the coding style and guidelines used by this repository, which must be followed for any new code.
- Variables, functions, methods, class members, namespaces, files: lowerCamelCase
- Classes, structs, enum classes, enum values, aliases, constexpr, static class variables: UpperCamelCase
- C-style defines: ALL_CAPS_WITH_UNDERSCORE_TO_SEPARATE_WORDS
- Class member names should start with an underscore
- Static variables should start with s_
- When enumerating a map/unordered_map using a for loop, name the iterator loop variable somethingKV (key/value)
- Prohibit C-style cast, use static_cast instead
- Prohibit C-style types (int, long, char), use cstdint types instead (std::int32_t, std::int8_t)
- Prohibit typedef keyword, use using instead
- Prohibit C-style enums, use enum class instead
- Always initialize non static data members (NSDM) except when impossible (when the data member is a reference), using brace initialization
- Always initialize structs fields using brace initialization to prevent UB in cases like this:
// Start with a struct defined like this
struct Foo
{
int a;
};
// Declare a variable bar of type Foo using aggregate initialization
auto const bar = Foo{5};
// At a later time, a new field is added to Foo so that it's now defined like this
struct Foo
{
int a;
int b;
};
// !!! The previously declared bar variable will still compile, as it is using aggregate initialization, but it will now have an unitialized field without knowing it !!!
// No such UB would have happened if Foo was defined like this
struct Foo
{
int a{0};
int b{0};
};
- Always specify the type to the right of the = sign when declaring a variable (and always use the = sign for the sake of consistency). Since c++17 and [dcl.init], there is no downside to this rule.
- Always use auto for variables declaration as it's impossible to have an uninitialized variable (possible since c++17 thanks to [dcl.init] update in P0135R1: Guaranteed copy elision)
- Always put const to the right of the type (for consistency and prevent ambiguity when used with auto and pointers)
- Add virtual and override keywords when overriding a virtual method for clarity and consistency
- Always declare function parameters as const (so they cannot be changed inside the function), except for obvious reasons (references, movable objects and pointers that are mutable)
- Always declare variables as const if they never change
- Current library public headers (using "")
- Current library private headers (using "")
- Other non-standard libraries public headers (using <>)
- Standard libraries public headers (using <>)
Separate each category with an empty line feed.
Example:
#include "la/avdecc/avdecc.hpp"
#include "entity.hpp"
#include <windows.h>
#include <boost/boost.hpp>
#include <vector>
- Don't use function parameter to return a value (except for in/out objects, but never for simple types), use the return value of the function (use pair/tuple/struct/optional if required). Except if absolutely required.
- A non-owning pointer passed to a function should be declared as & if required and * if optional
- Never pass a shared_pointer directly if the function does not participate in ownership (taking a count in the reference)
- Never pass to a function a dereferenced non local shared_pointer (sptr.get() or *sptr, where sptr is global or is class member that can be changed by another thread or sub-function). Take a reference count before dereferencing.
- Always handle all cases in a switch-case statement (make use of the default keyword if required)
- Always scope statement blocs with curling braces when it's optional (if, else, ...)
Use the provided clang-format file to correctly format the code.
- A patched version of the clang-format binary is required (fixing issues in baseline code)
- clang-format version 7.0.0 (with the patch applied: clang-7.0.0-BraceWrappingBeforeLambdaBody.patch)
- Precompiled clang-format with patch applied, for windows and macOS, can be found here
TBD / WIP