Mainly inspired by https://google-styleguide.googlecode.com/svn/trunk/cppguide.html
Code style
Please follow the scripts/clang-format coding style. We also provide a pre-commit hook that checks the committed files are correctly formatted (see Pre commit hook).
- Indentation style : 4-spaces
- Brace style : keep it consistent across files.
- Case style : CamelCase
- Only classes have their first letter capitalized. Functions and variables don't.
- Class members have the
m_
prefix. Other prefixes (apart from g_
for globals, and s_
for static classe members) are discouraged.
- no ifs / for / while one-liners. Braces everywhere. Even for cases in a switch.
- separate different clauses in a boolean expression with parens.
( (a || b) && ( c+d < 0) )
- use c++ style casts unless converting a value (e.g.
int x = int(f))
. Avoid const_cast
if possible.
- use prefix increments (
++i
and not i++
)
- use
const
everywhere possible. use constexpr
for const values.
- line length should be kept at 80 (soft limit) and not exceed 120 (hard limit)
- no need for () for a return statement
- document using doxygen convention, special commands with backslash \ (e.g.
\brief
rather than @brief
).
Headers
- Every .cpp must have an associated .hpp file
- oneline inline can be defined in class
- complex inline methods are defined out of class in .hpp
- Two types of include guards are accepted (modern is preferred):
- Modern:
#pragma once
- Legacy:
#ifndef HEADER_NAME_HPP_
- Every class should have its own header.
- Always use < > in include directives and never " "
- Keep headers in order : Class header, other headers from project, system libraries, other libraries.
- forward declare as much as you can
Functions
- use const reference or value to pass input parameters
- use references for passing output parameters
- output parameters appear last.
Scope and names
- use anonymous namespaces for file local variables / functions. no classes with only static functions !
- Use
namespace Ra { }
for all radium engine code, plus a sub-namespace for each module (e.g. Ra::Physics
)
- never use the
using
instruction for a whole namespace
- put all non member functions in a namespace (no top level global functions)
- declare pointers and ref attached to their type :
void* a
, const Foo& bar
- macros and defined constants should be in capitals.
Variables
- declarations should always be made on separate lines; (no
int a, b, c;
)
- initialize variables on the line of declaration whenever possible
- no global variables. If really necessary, prefix with
g_
- use C++11
nullptr
for null pointers.
- use
auto
only when it helps readability.
Scalar types
- Radium defines a default type
Scalar
, set either as float
or double
depending on the cmake option RADIUM_WITH_DOUBLE_PRECISION
- Always use
Scalar
type to represent floating point numbers, except when interfacing with external libraries using a fixed floating point type (e.g. Qt).
- Radium offers operators to create
Scalar
from integer and floating point numbers: always use Scalar()
or _ra
suffix when defining numbers from literals (e.g. auto a = .5_ra;
, Scalar b = a * Scalar( 2 );
or Scalar c = a / 2_ra;
).
- Equality between Scalar values needs to be computed using
Ra::almost_equals
(see CoreMacros.hpp).
Class design
- Constructors should be trival. All complex work goes in an
init()
function
- Try to order class members by size (biggest to smallest)
- Try to declare these fixed-size vectors all together, and preferably first in the class.
- Never pass a fixed-size vector by value to a function (only ref and const ref). Using them as return value is fine.
- use
explicit
for all one-arguments constructors
- use
= delete
for preventing copy constructor and other compiler-generated functions
- use
= default
for default compiler-generated function (copy constructor, assignment operator)
- use
struct
for trivial PODs where all data is public and class
for everything else.
- no other inheritance than public
- if multiple inheritance, all parent classes but one have to be interfaces (= pure virtual classes)
- composition is better than inheritance
- if the class has virtual methods then the destructor is virtual
- use
override
when overriding a virtual method.
- use operator overloading only if the meaning is non-ambiguous (only for arithmetic-like syntax).
- be consistent with operators (i.e. if you overload + and = also overload +=).
- declare : public functions (constructors first), private functions, public variables, private variables.
- declare nested types and enums before functions
- do not abuse function overloading.
- avoid
mutable
- getters and setter should have a consistent name with the variable.
Non-negociable
- Exceptions are forbidden, except when mimicking or using
std
containers (e.g., by throwing std::out_of_range
). In any cases, exceptions must be used in exceptional cases, and should not be used as an event system.
- No gotos.