CPP Style Guide and Recommendations - epfl-lasa/wiki GitHub Wiki
C++ is a beast of a language - it is traditional, and it is modern. It is so close, and yet so far, from base C. It lets you get incredibly close to the hardware and manage every bit of memory yourself, and at the same time it provides incredible abstraction patterns.
Within LASA, where people's experience and ambitions with coding projects are diverse, the aim of this page is not to militantly enforce modern, gold-standard programming. Rather, we just want code to be consistent and readable so we can focus on actual research problems.
The Google C++ Style Guide has been widely adopted as good and safe practice. It is not without its flaws, and can be quite restrictive particularly towards modern use of the language. Still, its rules are clear and provide a solid foundation for shared code projects.
The ANYbotics ANYmal Research C++ Style Guide makes a few minor adaptations to the base Google style in the context of robotics research, and is the recommended reference for LASA.
To further promote readability and usability within LASA, some additional minor changes have been suggested below. Read and adopt the summary below first, then use the ANYbotics guide for everything else.
Use this guide in conjunction with the Git best practices and pull request guidelines and aim for incremental improvement to your code quality and usability with each new commit.
All the greatest code is written one line at a time.
Write code in clear, readable, well-scoped blocks; prefer using multiple specific sub-functions in place of one big function. Document your code with a README and inline comments wherever the usage or behaviour is not painfully obvious.
Keep your code portable - don't hardcode file paths, environment variables or OS-specific behaviour if it can be avoided. If your code requires external dependencies to run, make sure you also provide installation and build instructions (CMakeLists, Dockerfile, README, etc).
Source files are *.cpp
, header files are *.h
. Filenames should be snake_case
unless it is declaring / implementing a class, in which case it should match the class name.
An example file structure is shown below. The first include
of a source file should be its relevant header file. Following that are built-in standard libraries, then external libraries, then LASA libraries from other modules / packages, and finally other headers from the local package.
For header files, define only the includes necessary for the declarations in that file. Put any further implementation dependencies in the related source file.
All code should be wrapped in a namespace scope where the name in lowercase
is easily relatable to your package.
#pragma once
#include "my_package/my_header_file.h"
#include <unistd.h>
#include <vector>
#include <ros/ros.h>
#include <Eigen/Core>
#include <other_lasa_package/Controller.h>
#include "my_package/control_helpers.h"
#include "my_package/typedefs.h"
namespace mypackage {
}
- Type names (including enums, structs, classes, typedefs, etc) should be in
UpperCamelCase
. Virtual classes should use the interface prefixI
. - All functions and variables, whether static or local, should be in
lowerCamelCase
, with the following exceptions; class private and protected data members should have an underscore suffix:lowerCamelCase_
. - When using enums, prefer
UPPER_SNAKE_CASE
for the members.
enum MyEnum {
DEFAULT = 0,
SECOND_CASE,
OTHER
};
struct MyStruct {
int publicDataMember;
};
class IMyVirtualClass {
public:
virtual void myVirtualFunction() = 0;
};
class MyClass : public IMyVirtualClass {
public:
void myVirtualFunction() override;
float getPrivateData() const;
float publicDataMember;
private:
float privateDataMember_;
};
void myFunction(const MyClass& readonlyReference, MyClass& mutableReference) {
int myLocalVariable;
}
- Indents are 2 spaces.
- Conditionals and loops always have brackets, with
else if
/else
statements following the closing bracket on the same line. No spaces inside parentheses. - In a
for
loop, place a space after;
, and on both sides of:
. -
switch
statements should define a default case. Only use additional scoping brackets within a case when necessary (e.g. declaring a local variable).
if (condition) {
foo();
} else if {
bar();
} else {
...
}
while (condition) {
foo();
}
for (int i = 0; i < 10; ++i) {
foo();
}
std::vector<SomeType> range(...);
for (auto iter : range) {
bar();
}
switch (value) {
case 0:
foo();
break;
case 1: {
float localVar;
bar();
break;
}
default:
case 2:
foo();
bar();
break;
}
Pointers and references in C++ are a great tool, but unfortunately also easy to get lost in. The ownership of the underlying data can be fuzzy and the correct cleaning up. For this reason, in modern C++ the smart pointers have been introduced. They bring much more clarity to your code and come with only a little overhead, for any larger project I advise using those. Find more information on: https://docs.microsoft.com/en-us/cpp/cpp/smart-pointers-modern-cpp?view=msvc-170
While it is useful to internalize the rules of this style guide while writing your code, it would be cumbersome and unrealistic to check every line against every rule manually. Fortunately, the majority of the formatting rules can be applied to your code automatically. By configuring your development environment to automatically format your code (for example, format on save), you can ensure that each new addition you make will conform to the lab standard without any effort on your part.
Some files have been provided to help automatically reformat your code according to the LASA style. Use the LASA style directly within your code editor by importing the IntelliJ IDEA code style XML. Alternatively, post-format your code using your editor or the clang-format
command-line tool with the clang-format-lasa file.
Follow the setup instructions below and within less than 5 minutes, your favourite code editor will automatically format your code in the future.
(Instructions written for Ubuntu 18.04)
clang-format is a tool to automatically format C/C++/Objective-C code. Install it on your computer with
sudo apt-get update
sudo apt install clang-format-10
Then, copy or symlink this file into the src
folder
of your catkin workspace. For example, place it on your computer here:
~/catkin_ws/src/.clang-format
ATTENTION: Do not rename this file! Otherwise it will not be found by clang-format. Now, any file inside your catkin workspace will be formatted according to the LASA C++ style guidelines described above.
You can run clang-format from the command line to format a single file as:
cd ~/catkin_ws/src/
clang-format-10 -i -style=file ./path/to/file.cpp
We do not advise you to use clang-format this way. Instead, find the instructions for your code editor below and let it take care of formatting your files.
Make the IntelliJ IDEA code style XML file available on your computer by either downloading it separately or cloning into this repository.
In CLion, go to File
→ Settings
→ Editor
→ Code Style
. Then, under Scheme
, click on
Show Scheme Actions
and then Import Scheme...
. Select the file you downloaded and confirm with Ok
.
Additionally, go to File
→ Settings
→ Plugins
and find the plugin called Save Actions in the marketplace.
Install this plugin, then go to File
→ Settings
→ Other Settings
→ Save Actions
. Check the box
Activate save actions on save
and then Reformat file
. Now, each time you save your file, it will automatically be reformatted.
Note that the Save Actions settings are project-specific, so you have to activate the save actions on save for every new
project that you open with CLion.
Alternatively, you can check the box Reformat code
under Before commit
in the VCS commit window if you don't want to use Save Actions.
First, install the C/C++ extension. Then, make sure
that the .clang-format
file is available in the root directory of your workspace, i.e. after follwoing the instructions above, open VS Code with
cd ~/catkin_ws/src/
code .
To configure the clang-format in VS Code, go to File
→ Preferences
→ Settings
and start typing clang
in the search bar.
If you have the C/C++ extension installed and enabled, option called C_Cpp: Clang_format_style
and C_Cpp: Formatting
will appear. Set their value to file
and clangFormat
, respectively.
Additionally, still in the settings, type save
in the search bar. Check the box Editor: Format On Save
such that the files
are automatically formatted on save. Change the option Editor: Format On Save Mode
to file
.
Finally, if you have used a different formatting tool before, go to any C++ file, right click in the editor, select Format Document With...
,
then select Configure Default Formatter
and choose C/C++
.
If you haven't already done so, install the Package Manager the usual way. Then, open the Command Palette with Ctrl + Shift + P
,
choose Package Control: Install Package
, and install the package named Clang Format.
Then, go to Preferences
→ Package Settings
→ Clang Format
→ Custom Style - User
. Copy and paste the content of this file.
Finally, go to Preferences
→ Package Settings
→ Clang Format
→ Settings - User
and make sure that the file looks like this:
{
"binary": "clang-format-10",
"style": "Custom",
"format_on_save": true,
"languages": ["C++", "C++11"]
}
- Enrico Eberhard ([email protected])
- Dominic Reber ([email protected])