The most reasonable approach would be relying on clang-format (or a similar tool).
Naming is about how to format a natural language phrase into a single C++ name (using letters’ case, underscores, abbreviations, prefixes, postfixes, etc). Regardless of the "rule" itself it must an established practices shared by all team members.
Code property | Rule | Example |
---|---|---|
The case | snake_case , applies to everything (a few exceptions follow later) |
std::string foo_bar( int baz_value ); |
Member data variable name |
|
class channel_t
{
// ...
private:
int m_id;
std::time_t m_last_activity_at;
};
struct message_t
{
int from_id;
int to_id;
std::string payload;
}; |
Static data variable name | No m_ -prefix |
struct foo_t
{
static inline int upper_limit = 42;
}; |
Namespaces |
|
namespace foo::bar_baz
{
// ...
} // namespace foo::bar_baz |
Functions (free/member/static) | No specific rules |
void foo_bar();
std::string buzz( int value ); |
Accessors/manipulators functions | Use the same name for "getter"/"setter" functions |
class some_t
{
public:
int precision() const;
void precision( int value );
private:
// ...
}; |
Template parameter naming | First_Capital_Snake |
template < typename My_Key, typename My_Value >
class storage_t
{
// ...
}; |
Abbreviations | "Well known" abbreviations are allowed |
lhs, rhs, dst, src, mngr, mgr, msg, tmp, init sptr, ptr, id, pos, cb, ec, err, svc, ctx, dir, min, max |
Struct and class names | Suffixed with _t for all cases (aliases follow the same rule) |
class my_thing_t;
using payload_t = std::string; |
Enum types |
|
enum class colours { red, green, blue };
enum class http_error_codes
{
ok = 200,
not_found = 404,
service_not_available = 503,
// ...
}; |
Input/output parameters ordering: output last. Try to avoid non-constant references in function parameters:
void make_description( int status, std::string & short_desc, std::string & detailed_desc );
Project directory should be some kind of varioation to the following:
<PROJECT_ROOT_DIR>
|
+---- cmake-scripts/ // Help scripts for cmake
|
+---- build-scripts/ // Help scripts for CI and dev build.
|
+---- <project_name>/
| |
| +---- include/
| |
| +---- src/
| |
| +---- test/
| |
| +---- CMakeLists.txt // Main project target defined here.
|
+---- CMakeLists.txt // Project root cmake-script.
Some practical rules:
- Associate namespaces with directories.
- Name of a directory must be a valid C++ name and follow namespace naming convention.
- Private headers in
impl
. details
namespace can be used without a dedicated directory.
*.hpp for headers *.cpp for compiled files *.ipp for inlined
The name itself must be the same (for some definition of same
) as the name of a major class if it has one (without _t
prefix) or the name that describes the content of a given file as clear as possible. Follow the principle of least surprise.
Rules for putting classes and functions into one file (aka component, a file pair (hpp/cpp)).
- If any entity in a given group of classes and functions cannot be used independently.
- Exception 1: small thing (flea on an alephand). If a small piece of logic adds some value to a “big” set of logic (classes and functions) while this “big” set of logic actually can be used independently (e.g. shift operators
>>, <<
for iostream, or fmt integrations). If this piece of logic makes sense for entities in a different source file, please, move it to another file. - Exception 2: domain specific set of "equal" classes (structs) introducing a vocabulary for some category of a given domain abstractions. Here the main "content" of a file is a vocabulary abstraction which is a single logical unit hence must be treated as a single class. While technically speaking some structs in a given set can be used separately we say that it is not that some specific types are used but the vocabulary is used and what is the subset of types of interest in a given code location are details of implementation using the vocabulary
- Exception 1: small thing (flea on an alephand). If a small piece of logic adds some value to a “big” set of logic (classes and functions) while this “big” set of logic actually can be used independently (e.g. shift operators
- Friendship. Friend classes and functions are favored to be located together. Unit tests can be an exceptions, however, this practice is discouraged from every day use.
- Cyclic dependencies: in general, it is a bad idea to draw cyclic dependencies, but sometimes you just have to. In such cases, it is definitely better to locate such classes and functions in the same physical location.
- Follow the principle of least surprise.
Section | Comment |
---|---|
Prologue | legal notice, project attribution |
Include guard | (header files) #pragma once |
Includes | Includes for file |
Content | Classes and function declaretion/definitions |
- An associated hpp-file (for cpp files)
- Std-header files
- 3rd parties libs headers
- Inhouse reusable libs
- Other sub-projects headers.
- This subproject headers
Use banners for definition/declaration.
//
// foo_type_t
//
class foo_type_t
{
// ...
};
//
// bar_func()
//
int bar_func( int x, int y )
{
// ...
}
- All C++ definitions (hence declarations) must be defined inside namespaces.
- Use anonymous namespaces for defining entities used only by a single cpp file.
Always try to comment your code: classes and functions and non-trivial design choices and algorithms.
Recommendation 1: comment tell the following:
- Purpose of a class or a function: what it does or what specific task it serves for.
- What it returns (for non-void functions).
- Essential behavior.
- Describe side effects if any.
- Reasonable preconditions/postconditions.
- Any important notes: alert of possible intuitive perception mistakes, thread-safety properties (if entity is considered to be used in such a context), non-functional states of a class etc.
- Write down initial author of commentary per non-trivial kludge (design inconsistencies, behaviour amusements, etc) that requires close attention.
- Usage examples.
Recommendation 2: it is better to write 10 comments perceived by you as useless and dumb and it would appear that you were right, than not to write them in those 10 cases and it would appear that in one of these cases your dumb comment would have been very helpful for another engineer.
To use 3rd-party libraries in a project use C++ package manager: Conan (my preference), Vcpkg, Hunter.