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
- Exceptions (
- Realtime type identification (
- Multiple inheritance and virtual base class (
- Nested templates (
printf-stlye I/O or fmtlib instead)
- Conversion operators
- C-style casts (use
- Friend functions/classes
- Only simple usecases of templates allowed (for example, defining a generic
complex_number<T>class). However, the complete STL is permitted. See also
- 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
- No recursive
- 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
operator<<for output streams,
operator()for functors and
operatorfor 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.
- Copy constructor and assignment operator are to be
=deleted (but move constructor/assignment allowed). All constructors must be marked
explicit. If one special member function is defined, then all the remaining must also be defined (either
= deleteas 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).
Useful compiler flags
-fno-commonwhich ensures that each global variable is only declared once, in a single object.
-fdata-sections, which split functions and data into their own ELF sections. This allows the linker to eliminate additional unused code when passed
- To unit test private/protected methods, consider
-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,
-fwrapv -fno-nonansi-builtins -fstack-protector -fsanitize.
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
- Template parameter names should use
- Class data members start with a leading
m_and static data members with a leading
- 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., just
- Use only C++ style comments (
&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