- Overview
- Naming scheme
- Comments and comment placement
- Line splitting
- Indentation, spacing, and braces.
- C++ Namespaces
- C preprocessor use
The following code sample shows various naming conventions used:
int gGlobalVar;
thread_local int tThreadLocalVar;
const int kConstGlobalVar;
int CapitalizedFunctionName(void);
static int AnotherCapitalizedFunctionName(void);
namespace lower {
} // namespace lower
class CapitalizedClassName {
public:
int CapitalizedMethodName(int parameter_name) {
int local_var_name = parameter_name;
return local_var_name;
}
static int gClassGlobal;
static const int kClassGlobalConstant;
};
enum EnumName {
kEnumeratorName
};
Guidelines:
- Almost all symbols that would traditionally be visible across function or module boundaries follow CapitalCase.
- C++ namespaces are lower-case, using underscores for word separation.
- Data (global or thread-local variables) are prefixed with
g
for global, mutable variables,k
for constant data that will not change, andt
for thread-local, mutable variables. It is permissible to useg
for thread-local variables.
As much as possible, use line comments, i.e. //
. The following code sample shows example of
comment placement.
// This is a comment about the function below.
void Function(void) {
// When a comment is the only thing on a line, then the prior line should be either empty, or if non-empty, contain
// a single `}`. Notice how there is an empty line between this comment and the prototype of the function above.
// Comments on a line should always be describe what is below them.
int var; // Comments after code on a line should be placed two spaces after what they are commenting.
Foo(true /* Embedded comment, usually to highlight the use of an optional parameter. */);
// This comment documents the conditions being tested in the following `if` statement. This comment should describe
// the "why" of the conditions being tested, not the "what". For example, if there is a special case that must be
// checked, describe the special case and how it relates to things.
if (gFoo) {
// This commnt documents the conditions being tested in the following `else if` statement.
} else if (gBar) {
}
}
namespace foo {
namespace {
} // namespace
} // namespace foo
To-do and notes (something that you think should be highlighted, or is particularly interesting, or that on your next viewing of the code is meant to jog your memory on how to interpret that code) should be written as follows.
TODO(pag): Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
NOTE(artem): Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Please indent split lines to align with the first word following the :
of your to-do or note. This helps
make such commends stand out from normal multi-line comments.
Notes and to-dos should always specify the (user)name of the person who wrote them. This is so that
when someone reads the note or to-do, they know who to ask about it (without having to search for it
via something like git blame
).
Anvill code is mostly broken around 80 columns. In practice, try to break lines before 90 columns. If you use an IDE, it is recommended that you configure it to add a margin line at 80 columns so that you know where the boundary is.
Function parameter and argument splitting is somewhat ad hoc. Use what you personally think is most readable or "pretty" when choosing between the approaches. The code sample below shows the two approaches.
Below, all parameters are moved to subsequent lines, and the first parameter is indented by four spaces.
std::pair<bool, bool> Node<QueryView>::CanonicalizeColumnPair(
COL *in_col, COL *out_col, const OptimizationContext &opt) noexcept;
// If we added even more parameters, the line splitting would keep going.
std::pair<bool, bool> Node<QueryView>::CanonicalizeColumnPair(
COL *in_col, COL *out_col, const OptimizationContext &opt,
COL *in_col, COL *out_col, const OptimizationContext &opt) noexcept;
Below, parameters are packed onto a line until they would exceed the margin, at which point they are
broken to the next line and indented to be aligned to column subsequent to the (
that introduces the
parameter list.
std::pair<bool, bool> Node<QueryView>::CanonicalizeColumnPair(COL *a, COL *b
COL *c) noexcept;
Below shows an example of line splitting for large conditional bodies. The conditional operator, &&
or
||
ends a line, and parenthesized sub-expressions introduce their own additonal single-space of
indentation.
if (!is_used_in_merge &&
!introduces_control_dep &&
!sets_condition &&
AllColumnsAreUsed()) {
Similarly:
if (!is_used_in_merge &&
(!introduces_control_dep ||
!sets_condition) && // Additional single space to align after `(`.
AllColumnsAreUsed()) {
Use your discretion to decide if the condition needs to be split across multiple lines. For example, the previous example would likely better be expressed as:
if (!is_used_in_merge &&
(!introduces_control_dep || !sets_condition) &&
AllColumnsAreUsed()) {
Anvill uses 2-space indendation. Tabs should not be used. If your editor / IDE supports automatic replacement of tabs with spaces then configure that feature accordingly.
C++ constructor initializer lists use four spaces of indentation before the :
, and then two spaces for
all subsequent fields (to align all of the field names).
Foo::Foo(void)
: field1(...),
field2(...) {}
Use the following code example as a guide for whitespace placement.
if (...) {
}
do {
} while (...);
for (;;) {
}
for (int i = 0; i < 10; ++i) {
}
Switch cases are indented two spaces, and then case bodies are further indented by two spaces.
switch (...) {
case 0:
break;
case 1:
default:
break;
}
You may use goto
statements, although please use them sparingly.
When using a goto
statement, indent the label in line with the nearest
enclosing }
. For example:
goto bar;
bar:
...
}
void Bar(void) {
if (...) {
goto foo;
foo:
...
}
}
All block statements must use braces. The above code sample is a good example of brace usage.
Switch cases are an example where the cases themselves do not need to use braces, unless they
introduce variables. If possible, use scoped initializers of if
statements to introduce braces into a
case statement. Below are some examples of brace uses with switch cases.
switch (...) {
case 0:
if (auto var = ...; var) {
...
}
break;
case 1: {
auto var = ...;
...
break;
}
}
All code should be defined as either belonging to a namespace, or explicitly be embedded within an
extern "C"
linkage scope.
Almost all code should be placed within the hyde
namespace, and code that is private to a translation
unit should be further embedded within an anonymous namespace. The code sample below provides an
example of proper usage.
namespace hyde {
namespace {
} // namespace
} // namespace hyde
Embedded namespaces should not be indented. The closing brace of a namespace should be commented with the namespace being closed.
When using linkage specifiers, either specify them inline, or like namespace.
extern "C" int InlineLinkageSpec(void);
extern "C" {
int NamespaceLikeLinkageSpec(void);
} // extern C
Never use the using namespace
feature of C++. Instead, prefer to always spell out foreign namespaces.
For example, always use std::vector
instead of using namespace std;
along with vector
.
Don't use C preprocessor macros for constant definitions. Instead, use constexpr
global variables, or use
enumerations (with a defined base type).
Try to only #inclde
what is used, preferring to forward-declare as much as possible to avoid excessive
#include
directives.