Skip to content

General formatting

Simon Gene Gottlieb edited this page Dec 7, 2020 · 8 revisions

Indention, general formatting

  • always indent by four spaces, no tabs allowed
    • indention larger than four may be used to achieve alignment (see below)
  • indent every scope, except namespaces
  • always place opening brace on newline
  • no trailing whitespaces. EVER.
  • maximum line length is 120.

Operators and parentheses

Some basic rules:

  • semicolon, comma ;, , – never a space before, always a newline or space after
  • arithmetic +, -, *, / – always a space before, always a newline or space after
  • logical && || – always a space before, always a newline or space after (do not use alternative and, or)
  • comparison ==, !=, <, >, <=, >= always a space before, always a newline or space after
  • bitshift/stream <<, >> – always a space before, always a newline or space after
  • subscript [, ] never a space before either, never a space after [
  • references &, && – always a space before, always a space after (unless variable omitted in function decleration)

Parenthesis ( and ):

  • do not use for casts, use c++ style casts instead (usually static_cast<>())
  • do not use for initialization, use brace-initialization instead {}
  • for, if, while
    • space between keyword and (, no space after (
    • no space before ), newline after )
  • function declarations, definitions and call – no space before, no space after (
  • if you don't close an open parenthesis, align the next lines after opening (

Splitting code over multiple lines:

  • in general, put operators at the end of the line and begin a word on the next line aligned with the corresponding word of the current line, e.g.:
if (foo &&
    bar &&
    bax)
//...

func(foo,
     bar,
     bax);

my_enum e = my_enum::FOO |
            my_enum::BAR |
            my_enum::BAX;
  • An exception to this rule is the pipe-symbol in the context of range and views where it is put on the beginning of the line, either aligned with a pipe-symbol on the previous line, or with the assignmen-operator:
auto v = foo | view::bar
             | view::bax;

auto v = view::myvee(foo)
       | view::myvee2
       | view::myvee3;

Braces

General:

  • opening braces always go on beginning of new line
    • only exception: tiny lambdas that completely fit into one line (including e.g. surrounding function)
  • always lead to indention of contents, except for namespaces
  • empty bodies can be closed on the same line as opening
  • otherwise the closing brace goes on a newline as well
  • always balance braces, i.e. if you have if and else and one body has braces, the other must, too.

Variable

General:

  • for all types that are not builtin arithmetic types, use brace initialization if at all possible (not () or =
  • initialise all variables upon declaration, unless you really know what you are doing (if in doubt, initialise with empty {})

const-ness:

  • when possible, make variable constexpr or const (in that order)
  • always use "east-const", i.e. put const on the right of the type that is modified; see http://slashslash.info/eastconst/ for more infos
  • if a variable is constexpr, put the constexpr on the left of the type (west-constexpr)

Global variables:

  • should be inline and constexpr

Examples I

// brace-initialize, don't use =
int i{7};
int & k{i};
float f{4.5};

// assignment
i = 8;
f = 3.4;

// loops
for (size_t j = 0; j < i; ++j)
    std::cout << j << '\n';

// linebreaks and alignment for readability
// in this case add braces, even for one-line body
for (size_t j = 0;
     (j < i) && some_very_long_condition_or_call();
     ++j)
{
    std::cout << j << '\n';
}

// always balance braces
if (i < 7)
{
    i = 21; // just one line
}
else
{
   i = 9;
   f = 13.3;
}

// tiny lambda may go in one line
auto f = [] (int & i) { ++i; }; 

// long lambda must not
std::for_each(v.begin(), v.end(), [] (int & i)
{
    i += 17;
    // ...
});

Functions

General:

  • use return type auto only if it actually improves readability
  • use trailing return type only when strictly necessary

Spacing (independent of declaration, definition or invocation):

  • no space before, no space after (
  • always a newline/; after ) except when using trailing return type

Linebreaks:

  • you may always put different argument on individual lines for improved readability, especially in function definitions
  • if you put one argument on an extra line, put each on it's own line
  • if you do, also do this for template arguments if you have a function template
  • if all arguments are on individual lines, but you still exceed line length 120, move constexpr or inline and the return value to it's own line

Alignment:

  • if you have linebreaks, align lines after opening (

  • place inline orconstexpr before the return type of the function (note that in contrast to variable definitions the constexpr keyword does not make the influence the return type of the function so it doesn't go to the right of the type)

Empty lines in function body:

  • No double-newlines, ever.
  • Always empty newline before new scopes if they are not part of if or a loop.
  • Always empty newline after } that closes a scope.
  • Newline after for-loop body that doesn't have {} is highly recommended
  • No strict rules otherwise; try to improve readability.
  • e.g. if a function only has three statements, it may be ok to not have any empty lines. If it is longer, group statements.

Classes and structs

TODO

Templates

General:

  • use typename, not class
  • don't use short concept forms
  • always put the requires clause on its own line
  • indent requires clause by four spaces
  • if one part of the function header is aligned, align also the rest

Spacing:

  • no space after opening < and no space before closing >
  • template declaration has space before opening
  • template usage or specialization has no space before opening
  • no space between multiple closing >

Linebreaks:

  • you may always put template parameters on individual lines for improved readability
  • you are required to to this for function templates where the function parameters are also on individual lines

Alignment:

  • if you have linebreaks, align lines after opening <

Examples

Functions and function templates

// small function, readable
inline void my_free_function(int const i, float const f)
{
    // ...
}

// larger header -> introduce linebreaks and alignment for readability
template <typename my_type,
          typename my_type2>
    requires std::is_integral_v<my_type> &&
             std::is_floating_point_v<my_type2>
inline void my_free_function(my_type const i,
                             my_type2 const f)
{
    // ...
}
Clone this wiki locally