A dialect of C++
C++ is a vast, complex and complicated language. When hundreds of developers are working on a project, we want to limit ourselves to a subset. There are many reasons to do (or not to do) so. Primarily, it is for readability and maintainability. You must face the truth that all the people who are working in a project do not have equal skill and knowledge about C++. Some are beginners, many are intermediate and a few are advanced in C++. You have to choose a subset of C++ because, unlike C or Go, you can’t store much of the language in your head. There have been such attempts earlier, but have been shot down by C++ evangelists. I particularly liked GCC C++ guidelines
Omitted features
- Exceptions (
-fno-exceptions -fno-non-call-exceptions
) - Realtime type identification (
-fno-rtti
) - Multiple inheritance and virtual base class (
-Wmultiple-inheritance -Wvirtual-inheritance
) - Nested templates (
-ftemplate-depth=N
) <iostream>
(useprintf
-stlye I/O or fmtlib instead)- Conversion operators
- C-style casts (use
static_cast<T>
instead) - Friend functions/classes
Limited features
- Only simple usecases of templates allowed (for example, defining a generic
swap<T>()
function orcomplex_number<T>
class). However, the complete STL is permitted. See also-Wtemplates
. - Only explicit use of templates is allowed. No implicit instantiations. This
helps to track how much memory each template instantiation would cause.
(
-fno-implicit-templates -fno-implicit-inline-templates
, avoid-frepo
). - No recursive
constexpr
functions (-fconstexpr-depth=1
) - Only pure virtual functions are allowed (for ex., abstract base class). Other uses of virtual functions are not permitted.
- Operator overloading is permitted only for numeric classes. Other valid
usecases are
operator<<
for output streams,operator()
for functors andoperator[]
for element access. Other operators shall not be overloaded. - Function overloading is allowed only if it is overloaded on single
paramter. For all other uses, use default arguments instead.
For example
split(std::string)
andsplit(const char*)
. - Copy constructor and assignment operator are to be
=delete
d (but move constructor/assignment allowed). All constructors must be markedexplicit
. If one special member function is defined, then all the remaining must also be defined (either= default
or= delete
as approrpiate). - Use public inheritance to describe ‘is-a’ relationships. Use protected inheritance for re-using an existing class in the implementation of a class hierarchy. Avoid private inheritance (prefer composition instead).
Other attempts
Useful compiler flags
-fno-common
which ensures that each global variable is only declared once, in a single object.-ffunction-sections
and-fdata-sections
, which split functions and data into their own ELF sections. This allows the linker to eliminate additional unused code when passed--gc-sections
.- To unit test private/protected methods, consider
-fno-access-control
. -fno-use-cxa-atexit
Some more: -Wall -Wextra -Wpedantic -Wshadow -Woverloaded-virtual -Wabi
-Wcast-qual -Wcast-align -Wfloat-equal -Wmissing-declarations
-Wmissing-include-dirs -Wctor-dtor-privacy -Wnon-virtual-dtor
. If you don’t
mind noisy output for extra caution, then -Weffc++
. For even more fun,
-Werror
.
Even more: -fwrapv -fno-nonansi-builtins -fstack-protector -fsanitize
.
Coding Style
Use astyle or clang-format with Mozilla-style. Naming style follows the convention of C++ Standard:
- Names of classes, members, functions, namespaces are all lowercase letters
separated with underscore
_
(i.e.snake-case
). - Template parameter names should use
CamelCase
. - Class data members start with a leading
m_
and static data members with a leadings_
. - Line length limited to 90 characters
- Define all members outside the class definition.
- Define member functions first, then member variables. Public members before non-public (in that order).
- Setter functions are like
set_value(int)
but getters don’t have any prefix, .i.e., justint value()
. - Use only C++ style comments (
//
normally,///
for doxygen). - Attach
*
and&
to type names, not variables. - Order of includes:
#include "my_class.hpp" // corresponding to my_class.cpp
#include <vector> // C++ Standard libraries
#include <fmtlib/posix.h> // Headers from dependencies outside project
#include "my_project.h" // Headers from current project