C++ Coding Guidelines¶
This how-to-guide describes best practices for developing C++ code for EVerest.
The aim is to have a consistent approach in order to avoid coding errors and aid with code maintenance.
This guide is aimed at new code contributions. Existing code can be updated but this should be in a separate pull request and not part of functionality changes.
See Contributing to EVerest for more information on how to contribute.
Before merging your contribution please ensure that the merged commit message is meaningful and describes the changes following review.
Code Layout¶
C++ code in EVerest is formatted via Clang Format and this is enforced
via the CI pipelines. This consistent approach is essential to aid with
code reviews ensuring that there are minimal (ideally none) formatting only
changes.
It is recommended to use the EVerest clang format container to reformat your code before submitting a pull request.
The EVerest clang format container ensures a consistent output using a specific
version of clang format. Unfortunately different versions of clang format
give different results even with the same .clang-format configuration file.
The docker container for clang-format is here.
File Naming¶
Historically different approaches have been used and it is recommended to be consistent with the existing code in the repository.
C++ files should use the extension
.cppC++ header files should use the extension
.hppC files should use the extension
.cC header files should use the extension
.hFor EVerest modules file names reflect the class contained within e.g. class
EvseManagerwould haveEvseManager.cppandEvseManager.hppFor library code file names are in snake_case and should reflect the class contained within e.g. class
OpenSSLProviderwould haveopenssl_provider.cppandopenssl_provider.hppheader files and implementation should be co-located in the same directory
private/internal headers should be in a separate directory (e.g. a sub-directory)
avoid mixing PascalCase and snake_case in the same filename
when a directory contains many files consider creating sub-directories to group functionality
Naming¶
classes, and structures, should be named using PascalCase starting with a capital letter
functions and methods should be in lower case snake_case
namespaces should relate to the directory hierarchy
enum values should be consistently named - i.e. avoid mixing PascalCase and snake_case
member variables should be snake_case starting with m_
function parameters should not match member variables or local variables
the this pointer should only be used when absolutely required
Example header file called ocpp/OcppDataModel.hpp:
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Pionix GmbH and Contributors to EVerest
/// \file Object to manage the OCPP data model
#pragma once
namespace ocpp {
class OcppDataModel : public OcppDataModelBase {
private:
int m_num_connectors{-1};
public:
OcppDataModel() = default;
OcppDataModel(int num_connectors) : m_num_connectors(num_connectors) {
}
/// \brief check if the object has been configured
/// \returns true when there is at least one connector
bool is_configured() const {
return m_num_connectors > 0;
}
/// \brief initialise with the count of connectors
/// \param[in] count - the number of detected connectors
void initialise(int count);
operator const OcppDataModelBase&() const {
return *this;
}
};
} // namespace ocpp
Example source file called ocpp/OcppDataModel.cpp:
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Pionix GmbH and Contributors to EVerest
namespace {
int internal_function(int parameter) {
return parameter * 4 + 1;
}
namespace ocpp {
void OcppDataModel::initialise(int count) {
m_num_connectors = internal_function(count);
}
} // namespace ocpp
Header Files¶
In general inline code should be avoided in header files however C++ templates will often require this and it may be needed for inlining.
Member variable initialisers should be provided. The following links gives examples of the different types and their uses:
e.g.
struct s {
std::string s3 = "hello"; // 1. copy-initialization
std::string s4 = {"hello"}; // 2. list-initialization (since C++11)
std::string s5{'a'}; // 3. list-initialization (since C++11)
};
List initialisation is preferred. Be consistent with usage and avoid mixing initialisation types (especially 2. and 3.).
Exceptions¶
There are always going to be occasions where departure from these guidelines is warranted. Comments should be used to explain the rationale for the difference.
It is recommended to match the existing style, or create a pull request that only updates the file to the new standards before making any code changes. This simplifies reviewing the pull request.
Coding Style¶
minimise the use of early returns from a function
try to keep functions short so they can be seen on a single screen
always include a
default:clause in a switch statementadd doxygen comments using
///and\brief…try to use meaningful variable names
use
#pragma onceas the include guardavoid throwing exceptions - keep use of exceptions contained within your class
use RAII where possible
use existing utility functions (*)
minimise external dependencies and ensure a compatible licence exists
design with testing in mind - ensure that your code can be unit tested
consider object life cycles and the impacts of multiple threads
add unit tests
there are a growing set of utility classes and functions in the lib directory. Including thread safe queues and object protection (monitor) and bit flags based on enumerations. Where possible use existing implementations and consider generalising new functions for inclusion into the
utillibrary.
If in doubt have a look at existing code and consider the Google style guide
Suggesting a Change¶
Zulip can be used as a starting point to interact with the community about a change, or enhancement. Once there is some consensus on an approach an issue should be raised in the EVerest github.
See Contributing to EVerest for more information on how to contribute.
Issues have a status:
Backlog - issue needs to be looked at
Ready - issue is ready for implementation
In Progress - issue is being worked on
In review - the updates are in review (e.g. pull request)
Done - the issue is closed
Please follow the issue template and add information such as the fork/branch where the issue is being looked at along with any pull request IDs.
It is especially important to check (the comments and status) before starting to work on an issue to ensure that someone else hasn’t already started to look at it.