-
Notifications
You must be signed in to change notification settings - Fork 82
General formatting
Simon Gene Gottlieb edited this page Dec 7, 2020
·
8 revisions
- 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.
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 alternativeand
,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)
- space between keyword and
- 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;
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
andelse
and one body has braces, the other must, too.
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
orconst
(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 theconstexpr
on the left of the type (west-constexpr)
Global variables:
- should be
inline
andconstexpr
// 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;
// ...
});
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
orinline
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 theconstexpr
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.
TODO
General:
- use
typename
, notclass
- 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
<
// 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)
{
// ...
}