Conventions de codage C++¶
Norme de codage C++ de l'organisation EIP-MemTide. Ce document est la reference unique et complete pour tous les depots C++ de l'organisation.
Le style est inspire des conventions C++ modernes d'Epic Games.
Portee¶
Cette norme s'applique a tout code C++ produit ou maintenu par l'organisation EIP-MemTide, sans exception. Elle couvre le nommage, les standards techniques, les commentaires, l'architecture de fichiers, le formatage et l'integration CMake.
Tout contributeur — membre ou externe — doit se conformer a ces regles avant de soumettre du code.
1. Langue¶
Tout le code, les commentaires, les noms de variables, les noms de fonctions, les chaines visibles par l'utilisateur (logs, erreurs, sortie console) et la documentation doivent etre rediges en anglais americain (U.S. English). Aucune exception.
2. Conventions de nommage¶
2.1 PascalCase partout¶
Convention : PascalCase pour tous les identifiants.
Obligatoire pour les classes, fonctions, methodes, variables, parametres, dossiers et fichiers. Premiere lettre en majuscule, sans underscores entre les mots.
class MyClass;
void CalculateTransform();
Int32 TotalLeaves;
2.2 Classes template¶
Convention : Prefixe T + PascalCase
template <typename ObjectType>
class TAttribute;
2.3 Enums¶
Convention : Prefixe E + PascalCase, valeurs avec prefixe court majuscule + underscore
enum class EColorBits { ECB_Red, ECB_Green, ECB_Blue };
- Les valeurs d'enum utilisent un prefixe court en majuscules derive du nom de l'enum, suivi d'un underscore.
- C'est une exception intentionnelle a la regle PascalCase sans underscore.
2.4 Variables booleennes¶
Convention : Prefixe b + PascalCase
bool bPendingDestruction;
bool bHasValidConnection;
2.5 Types et variables¶
Convention : Noms (substantifs). Pas de noms a une lettre.
/* Mauvais */ for (Int32 I = 0; I < MaxIterations; ++I) { ... }
/* Bon */ for (Int32 IterationIdx = 0; IterationIdx < MaxIterations; ++IterationIdx) { ... }
2.6 Methodes¶
Convention : Verbes decrivant l'effet ou la valeur de retour.
/* Mauvais */ void Calculation(); bool Ready() const;
/* Bon */ void CalculateTransform(); bool IsHardwareReady() const;
2.7 Macros¶
Convention : Prefixe projet + SCREAMING_SNAKE_CASE. Chaque projet definit son propre prefixe court en majuscules.
#define MYPROJ_PLATFORM_LINUX
#define MYPROJ_LOG_ERROR(...)
2.8 Tableau recapitulatif¶
| Element | Convention | Exemple |
|---|---|---|
| Classes, fonctions, methodes, variables | PascalCase |
MyClass, CalculateTransform() |
| Classes template | T + PascalCase |
TAttribute |
| Enums | E + PascalCase |
EColorBits |
| Valeurs d'enum | Prefixe majuscule + _ + PascalCase |
ECB_Red |
| Booleens | b + PascalCase |
bPendingDestruction |
| Macros C++ | Prefixe projet + SCREAMING_SNAKE_CASE |
MYPROJ_PLATFORM_LINUX |
| Dossiers | PascalCase |
MySubModule |
| Fichiers | PascalCase |
MyClass.hpp |
2.9 Exception — code kernel (BPF)¶
Les fichiers de code kernel-space (.bpf.c, .bpf.h) suivent les conventions du noyau Linux (snake_case) au lieu de PascalCase. Ceci est impose par le style de codage du noyau et les contraintes de la toolchain BPF. Cette exception ne doit jamais etre etendue au code userspace.
3. Standards techniques¶
3.1 Scoping explicite¶
Regle : using namespace ... est strictement interdit. Utiliser les namespaces explicites pour prevenir les collisions de symboles (void MyNamespace::MyClass::Method()).
3.2 Pointeurs¶
Regle : Utiliser nullptr, jamais NULL. Le macro C NULL n'est pas autorise.
3.3 Typage explicite¶
Regle : Eviter auto. Le type doit etre visible a la lecture, sans tooltips IDE.
Exceptions autorisees : - Liaison d'une lambda a une variable. - Variables d'iterateur dont le type est verbeux et nuit a la lisibilite.
/* Interdit */ auto Result = CalculateOffset(Base, Size);
/* Autorise */ auto OnComplete = [this](Int32 Status) { HandleCompletion(Status); };
/* Autorise */ auto Iterator = MyContainer.begin();
3.4 Gestion memoire¶
Regle : new/delete manuels interdits — utiliser RAII et les pointeurs intelligents.
| Situation | Outil |
|---|---|
| Propriete exclusive | std::unique_ptr |
| Propriete partagee | std::shared_ptr |
| Reference non-proprietaire | std::weak_ptr ou pointeur brut |
| Allocation sur la pile | Variables locales, std::array |
/* Interdit */ MyClass *Object = new MyClass(); delete Object;
/* Bon */ std::unique_ptr<MyClass> Object = std::make_unique<MyClass>();
3.5 Const-correctness¶
const et constexpr sont autant de la documentation que des directives compilateur. Principe directeur : transmettre l'information au compilateur le plus tot possible.
Regles :
- Passer les arguments par pointeur ou reference const s'ils ne sont pas modifies.
- Marquer les methodes const si elles ne modifient pas l'objet.
- Utiliser const pour l'iteration sur les conteneurs si la boucle ne modifie pas le conteneur.
void SomeMutatingOperation(MyResult& OutResult, const std::vector<Int32>& InArray)
{
/* InArray ne sera pas modifie, mais OutResult le sera */
}
void MyClass::SomeNonMutatingOperation() const
{
/* Cette methode ne modifie pas l'objet */
}
Ne jamais utiliser const sur un type de retour (inhibe la move semantics). Ne s'applique qu'au type de retour lui-meme, pas au type cible d'un pointeur ou reference retourne.
/* Mauvais */ const std::vector<std::string> GetNames();
/* Bon */ const std::vector<std::string>& GetNames();
3.6 Constexpr et consteval¶
Regle : Preferer constexpr a const pour les valeurs connues a la compilation.
/* Mauvais */ const Int32 MaxPoolSize = 1024;
/* Bon */ constexpr Int32 MaxPoolSize = 1024;
- Marquer les fonctions
constexprquand leur logique permet l'evaluation a la compilation.
constexpr Size AlignTo(Size Value, Size Alignment)
{
return (Value + Alignment - 1) & ~(Alignment - 1);
}
static_assert(AlignTo(13, 8) == 16);
- Utiliser
if constexprpour le branchement compile-time dans les templates au lieu de SFINAE ou du tag dispatch.
template <typename T>
void Process(T Value)
{
if constexpr (std::is_integral_v<T>)
ProcessInteger(Value);
else
ProcessFloat(Value);
}
constevalpeut etre utilise pour garantir l'evaluation a la compilation quand aucun fallback runtime ne doit exister (ex. : layout memoire, generation de hash statique).
consteval Size ComputeBlockSize(Size PageSize, Size HeaderSize)
{
return PageSize - HeaderSize;
}
4. Limites de complexite¶
| Metrique | Limite |
|---|---|
| Lignes par fonction | 100 max |
| Statements par fonction | 50 max |
| Parametres par fonction | 6 max |
Si une fonction depasse ces limites, elle doit etre decomposee en sous-fonctions.
5. Commentaires¶
5.1 Regles generales¶
- Tous les commentaires doivent etre en anglais.
- Commentaires sobres — concis, factuels, sans verbiage inutile.
- Pas d'emojis, d'ASCII art ou d'elements decoratifs. Ton professionnel en permanence.
- Ecrire du code auto-documentant :
/* Mauvais */ t = s + l - b;
/* Bon */ TotalLeaves = SmallLeaves + LargeLeaves - SmallAndLargeLeaves;
- Ecrire des commentaires utiles. Expliquer le pourquoi, pas le comment.
- Refactoriser plutot qu'expliquer. Ne pas sur-commenter du code mal ecrit ; le reecrire.
- Ne pas contredire le code. Mettre a jour les commentaires quand la logique change.
- Les commentaires doivent etre concis (une ligne max). Ne pas repeter ce que la signature dit deja. Pas de commentaire vaut mieux qu'un commentaire redondant.
5.2 Standard Doxygen¶
Convention : Style triple-slash /// exclusivement. Les autres formats (/** */) sont interdits.
/// @brief Checks if the hardware layer is initialized and ready.
/// @param TimeoutMs Maximum wait time in milliseconds.
/// @return True if the hardware is ready to receive commands.
bool IsHardwareReady(Int32 TimeoutMs) noexcept;
Tags Doxygen courants :
| Tag | Usage |
|---|---|
@brief |
Description courte (obligatoire) |
@details |
Description longue (optionnel) |
@param |
Description d'un parametre |
@return |
Description de la valeur de retour |
@tparam |
Description d'un parametre template |
@note |
Remarque importante |
@warning |
Avertissement |
6. Conventions de fichiers¶
6.1 Extensions¶
| Extension | Usage |
|---|---|
.hpp |
Declarations uniquement. Pas de logique. |
.inl |
Implementations de templates. |
.cpp |
Implementations non-template. |
6.2 Protection des headers¶
Regle : #pragma once en haut de chaque header. Les gardes #ifndef/#define classiques ne sont pas autorisees.
6.3 Architecture de fichiers¶
Les repertoires Include/ et Source/ sont symetriques : chaque module possede un sous-dossier dans les deux arborescences, et les noms doivent correspondre.
Include/MyModule/MyClass.hpp Declarations
Source/MyModule/CMakeLists.txt Build definition
Source/MyModule/MyClass.cpp Implementations
Header (Include/MyModule/MyClass.hpp) :
#pragma once
namespace MyModule
{
class MyClass
{
public:
void DoWork();
private:
Int32 WorkCount;
};
}
Implementation (Source/MyModule/MyClass.cpp) :
#include "MyModule/MyClass.hpp"
void MyModule::MyClass::DoWork()
{
...
}
Template (.inl) — le fichier .inl est inclus a la fin du .hpp correspondant :
// Include/MyModule/TContainer.hpp
#pragma once
namespace MyModule
{
template <typename T>
class TContainer
{
public:
void Add(const T& Item);
};
}
#include "MyModule/TContainer.inl"
7. Architecture et CMake¶
7.1 Structure modulaire¶
Chaque module est une bibliotheque statique et contient un CMakeLists.txt a sa racine dans Source/.
project_add_module(MyModule)
# Optionnel : dependances
target_link_libraries(MyModule PUBLIC MyDependency)
La macro project_add_module (ou equivalent specifique au projet) collecte les sources dans Source/, expose les headers de Include/ et cree une cible statique linkable par les autres modules.
7.2 Dependances¶
Les modules declarent leurs dependances via target_link_libraries. Les dependances transitives sont gerees par CMake.
target_link_libraries(MyModuleB PUBLIC MyModuleA)
8. Formatage¶
8.1 Regles de base¶
| Regle | Valeur |
|---|---|
| Indentation | 4 espaces (pas de tabulations) |
| Largeur maximale | 120 colonnes |
| Style d'accolades | Allman |
| Liaison des pointeurs | A droite (int *Ptr) |
| Espaces dans les parentheses | Non |
| Espace avant parentheses de fonction | Non |
8.2 Style Allman¶
Les accolades ouvrantes sont toujours sur une nouvelle ligne, alignees avec le bloc parent.
if (bIsReady)
{
Initialize();
}
else
{
WaitForReady();
}
class MyClass
{
public:
void DoWork();
private:
Int32 ItemCount;
};
8.3 Application automatique¶
Le formatage est applique par clang-format. Toujours formater le code avant de committer. Les hooks de pre-commit bloquent le code non conforme.
9. Patrons interdits — resume¶
| Patron | Alternative |
|---|---|
using namespace ... |
Namespaces explicites |
NULL |
nullptr |
auto (sauf exceptions) |
Type explicite |
/** */ Doxygen |
/// exclusivement |
const sur type de retour |
Retourner par valeur ou reference const |
new/delete manuels |
std::unique_ptr, std::shared_ptr |
#ifndef guards |
#pragma once |
| Commentaires en francais | Anglais U.S. uniquement |
| Emojis, ASCII art | Ton professionnel |
10. Checklist avant soumission¶
Avant chaque pull request, verifier :
- Le code compile sans warnings (
-Wall -Wextra -Wpedantic) - Le formatage est conforme (
clang-format) - L'analyse statique passe (
clang-tidy) - Pas de
new/deletemanuels — RAII et pointeurs intelligents - Fonctions < 100 lignes, < 6 parametres
- Tests unitaires ajoutes/mis a jour
- Commentaires Doxygen
///sur les nouvelles API publiques - Tous les commentaires et le code en anglais
- Pas d'
autosauf exceptions autorisees - Const/constexpr correctness respectee