C++ Style Conventions#
Apply these when writing or reviewing C++. This document covers style: naming, file and API structure, and comments, i.e. how the code reads.
Mechanical formatting (indentation, spacing, brace placement, line wrapping, pointer alignment, the 120-column limit, namespace-close comments, preprocessor-directive indentation) is applied automatically by the repository’s .clang-format. These conventions deliberately omit those rules so they stay focused on what clang-format cannot do: naming, structure, and semantics. Do not spend effort hand-formatting; run clang-format.
When you touch existing code, fix style within the lines you add or change; leave untouched surrounding lines alone rather than reformatting the whole file.
Worked examples#
The highest-frequency style fixes; the same reasoning generalizes to the rules below.
Member naming:
Before: int m_count;
After: int count_;
Global constant:
Before: const int DAYS_IN_WEEK = 7;
After: constexpr int kDaysInAWeek{7};
Uniform initialization:
Before: std::string name = "abc";
After: std::string name{"abc"};
Naming#
Files and variables are
snake_case. Namespaces aresnake_caseand follow thescore::...hierarchy.Types (classes, structs, enums, aliases) are
PascalCasewith no underscores; even well-known acronyms are not all-caps (XmlStreamReader, notXMLStreamReader).Functions and methods are
PascalCase(MaxConcurrencyLevel()).Class data members carry a trailing underscore (
memory_resource_); struct members do not. Exception:static constexpr/static constclass constants use thek-prefix constant rule below (kMask, notmask_).k-prefix everyconst/constexprwith static storage duration and a fixed value: namespace-scope constants andstatic constexpr/static constclass members (kDaysInAWeek,static constexpr std::uint8_t kMask{...};). Optional for localconstexprvariables. Enumerators also take thekprefix; prefer scoped enums (enum class), and only an enumerator in the global namespace embeds the type name (kUrlTableErrors_Ok). Mutable global variables are not used (MISRA 6.7.2 forbids them).Macros are a last resort (MISRA 19.0.2 bans function-like macros); when unavoidable, name them
UPPER_CASE_WITH_UNDERSCORES.Be descriptive. Avoid abbreviations except ones that are well known outside the project (
url,dns), and never abbreviate by dropping letters (error_count, noterror_cnt). Types and variables are nouns; functions read as imperative verbs.Function parameter order is inputs, then inputs/outputs, then outputs.
Non-type template parameters follow the variable convention; type template parameters are
PascalCase, commonly suffixed...Type.
Files and headers#
One class per translation unit:
class_name.h/class_name.cpp, tests inclass_name_test.cpp, mocks inclass_name_mock.h/class_name_mock.cpp. Library folder names aresnake_case.A file opens with the copyright header, then the include guard.
#pragma onceis not allowed.Include-guard name: the file path uppercased,
/and.replaced by_, soscore/result/error.hbecomesSCORE_RESULT_ERROR_H.Use
"..."for project headers and<...>for system and external headers, and include the file’s own header first. clang-format sorts includes within each block.Definitions of inline functions belong in a header.
Classes#
Declaration order:
public, thenprotected, thenprivate. Within each section: aliases/enums, constructors, destructor, methods, data members.frienddeclarations go in theprivatesection. The.cppdefines members in the same order.List constructor initializers in member-declaration order, so run order matches the source and there is no
-Wreorderwarning.Interfaces do not use an
Iprefix: the interface keeps the plain name (Executor), the implementation takes anImplsuffix (ExecutorImpl), and the mock aMocksuffix (ExecutorMock). A pure interface declares a non-purevirtualdestructor so deletion through the interface pointer is well defined.
Idioms#
Semantic and declaration rules that .clang-format cannot apply, so apply them yourself:
Brace-initialize uniformly (
int x{3};), notint x = 3;; clang-format will not convert=to braces.Declare only one pointer variable per line (
char* a;thenchar* b;, neverchar* a, *b;).Do not wrap a
returnvalue in unnecessary parentheses.Prefer named constants over bare literals,
nullptr, ortrue/falsepassed as arguments, so the call site explains itself.
Comments#
//for ordinary comments,///for Doxygen; prefix Doxygen tags with@(@brief,@param,@return).On a public declaration,
@briefis mandatory; add@param/@returnwhen non-trivial. Document ownership transfer, whether arguments may benullptr, the lifetime of retained references, thread-safety assumptions, and performance implications. A comment at the definition explains how the code works rather than repeating the declaration.Class data members get a short Doxygen comment describing their purpose and any sentinel values.
Use
@todowith the associated GitHub issue for non-trivial TODOs. Mark deprecated APIs with the C++[[deprecated("use NewApi instead")]]attribute.