> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-fbfa8bee.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Guide de style pour le code C++ de ClickHouse

# Guide de style C++

<div id="general-recommendations">
  ## Recommandations générales
</div>

Ce qui suit relève de recommandations, et non d'exigences.
Si vous modifiez du code, il est logique de respecter la mise en forme du code existant.
Un style de code est nécessaire pour garantir la cohérence. La cohérence facilite la lecture du code et les recherches dans le code.
Nombre de ces règles n'ont pas de justification logique ; elles découlent des pratiques établies.

<div id="formatting">
  ## Formatage
</div>

**1.** La majeure partie de la mise en forme est effectuée automatiquement par `clang-format`.

**2.** L'indentation est de 4 espaces. Configurez votre environnement de développement de sorte qu'une tabulation ajoute quatre espaces.

**3.** Les accolades ouvrantes et fermantes doivent figurer sur une ligne distincte.

```cpp theme={null}
inline void readBoolText(bool & x, ReadBuffer & buf)
{
    char tmp = '0';
    readChar(tmp, buf);
    x = tmp != '0';
}
```

**4.** Si le corps entier de la fonction est un seul `statement`, il peut être placé sur une seule ligne. Ajoutez des espaces autour des accolades (à l'exception de l'espace en fin de ligne).

```cpp theme={null}
inline size_t mask() const                { return buf_size() - 1; }
inline size_t place(HashValue x) const    { return x & mask(); }
```

**5.** Pour les fonctions. Ne pas mettre d'espaces autour des parenthèses.

```cpp theme={null}
void reinsert(const Value & x)
```

```cpp theme={null}
memcpy(&buf[place_value], &x, sizeof(x));
```

**6.** Dans les expressions `if`, `for`, `while` et autres, une espace est insérée avant la parenthèse ouvrante (contrairement aux appels de fonction).

```cpp theme={null}
for (size_t i = 0; i < rows; i += storage.index_granularity)
```

**7.** Ajoutez des espaces autour des opérateurs binaires (`+`, `-`, `*`, `/`, `%`, ...) et de l'opérateur ternaire `?:`.

```cpp theme={null}
UInt16 year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0');
UInt8 month = (s[5] - '0') * 10 + (s[6] - '0');
UInt8 day = (s[8] - '0') * 10 + (s[9] - '0');
```

**8.** Si un saut de ligne est saisi, placez l'opérateur sur une nouvelle ligne et augmentez l'indentation qui le précède.

```cpp theme={null}
if (elapsed_ns)
    message << " ("
        << rows_read_on_server * 1000000000 / elapsed_ns << " rows/s., "
        << bytes_read_on_server * 1000.0 / elapsed_ns << " MB/s.) ";
```

**9.** Vous pouvez utiliser des espaces pour aligner le contenu au sein d'une ligne, si vous le souhaitez.

```cpp theme={null}
dst.ClickLogID         = click.LogID;
dst.ClickEventID       = click.EventID;
dst.ClickGoodEvent     = click.GoodEvent;
```

**10.** N'utilisez pas d'espaces autour des opérateurs `.`, `->`.

Si nécessaire, l'opérateur peut être renvoyé à la ligne suivante. Dans ce cas, le décalage qui le précède est augmenté.

**11.** N'utilisez pas d'espace pour séparer les opérateurs unaires (`--`, `++`, `*`, `&`, ...) de l'argument.

**12.** Placez un espace après une virgule, mais pas avant. La même règle s'applique au point-virgule à l'intérieur d'une expression `for`.

**13.** N'utilisez pas d'espaces pour séparer l'opérateur `[]`.

**14.** Dans une expression `template <...>`, insérez un espace entre `template` et `<` ; pas d'espace après `<` ni avant `>`.

```cpp theme={null}
template <typename TKey, typename TValue>
struct AggregatedStatElement
{}
```

**15.** Dans les classes et les structures, écrivez `public`, `private` et `protected` au même niveau que `class/struct`, et indentez le reste du code.

```cpp theme={null}
template <typename T>
class MultiVersion
{
public:
    /// Version of object for usage. shared_ptr manage lifetime of version.
    using Version = std::shared_ptr<const T>;
    ...
}
```

**16.** Si le même `namespace` est utilisé pour l'ensemble du fichier et qu'il n'y a rien d'autre de significatif, aucun décalage n'est nécessaire à l'intérieur du `namespace`.

**17.** Si le bloc d'une expression `if`, `for`, `while` ou autre ne contient qu'une seule `statement`, les accolades sont facultatives. Placez la `statement` sur une ligne séparée à la place. Cette règle s'applique également aux `if`, `for`, `while` imbriqués, ...

Mais si l'`instruction` interne contient des accolades ou `else`, le bloc externe doit également être entouré d'accolades.

```cpp theme={null}
/// Finish write.
for (auto & stream : streams)
    stream.second->finalize();
```

**18.** Il ne doit pas y avoir d'espaces en fin de ligne.

**19.** Les fichiers sources sont encodés en UTF-8.

**20.** Les caractères non-ASCII peuvent être utilisés dans les littéraux de chaîne de caractères.

```cpp theme={null}
<< ", " << (timer.elapsed() / chunks_stats.hits) << " μsec/hit.";
```

**21.** N’écrivez pas plusieurs expressions sur une même ligne.

**22.** Regroupez les sections de code à l’intérieur des fonctions et ne les séparez pas par plus d’une ligne vide.

**23.** Séparez les fonctions, les classes, etc. par une ou deux lignes vides.

**24.** `A const` (associé à une valeur) doit être écrit avant le nom du type.

```cpp theme={null}
//correct
const char * pos
const std::string & s
//incorrect
char const * pos
```

**25.** Lors de la déclaration d’un pointeur ou d’une référence, les symboles `*` et `&` doivent être entourés d’espaces.

```cpp theme={null}
//correct
const char * pos
//incorrect
const char* pos
const char *pos
```

**26.** Lorsque vous utilisez des types template, donnez-leur un alias avec le mot-clé `using` (sauf dans les cas les plus simples).

Autrement dit, les paramètres du template sont spécifiés uniquement dans `using` et ne sont pas répétés dans le code.

`using` peut être déclaré localement, par exemple à l'intérieur d'une fonction.

```cpp theme={null}
//correct
using FileStreams = std::map<std::string, std::shared_ptr<Stream>>;
FileStreams streams;
//incorrect
std::map<std::string, std::shared_ptr<Stream>> streams;
```

**27.** Ne déclarez pas plusieurs variables de types différents dans une seule instruction.

```cpp theme={null}
//incorrect
int x, *y;
```

**28.** N'utilisez pas de transtypages de style C.

```cpp theme={null}
//incorrect
std::cerr << (int)c <<; std::endl;
//correct
std::cerr << static_cast<int>(c) << std::endl;
```

**29.** Dans les classes et les structs, regroupez séparément les membres et les fonctions dans chaque scope de visibilité.

**30.** Pour les petites classes et les petits structs, il n'est pas nécessaire de séparer la déclaration des méthodes de leur implémentation.

Il en va de même pour les petites méthodes, dans n'importe quelle classe ou struct.

Pour les classes template et les structs template, ne séparez pas les déclarations des méthodes de leur implémentation (car sinon, elles doivent être définies dans la même unité de traduction).

**31.** Vous pouvez revenir à la ligne à 140 caractères, au lieu de 80.

**32.** Utilisez toujours les opérateurs de pré-incrémentation/prédécrémentation si la forme postfixée n'est pas nécessaire.

```cpp theme={null}
for (Names::const_iterator it = column_names.begin(); it != column_names.end(); ++it)
```

<div id="comments">
  ## Commentaires
</div>

**1.** Veillez à commenter toutes les parties non triviales du code.

C’est très important. Le simple fait de rédiger un commentaire peut vous faire comprendre que le code n’est pas nécessaire ou qu’il est mal conçu.

```cpp theme={null}
/** Part of piece of memory, that can be used.
  * For example, if internal_buffer is 1MB, and there was only 10 bytes loaded to buffer from file for reading,
  * then working_buffer will have size of only 10 bytes
  * (working_buffer.end() will point to position right after those 10 bytes available for read).
  */
```

**2.** Les commentaires peuvent être aussi détaillés que nécessaire.

**3.** Placez les commentaires avant le code qu’ils décrivent. Dans de rares cas, ils peuvent aussi se trouver après le code, sur la même ligne.

```cpp theme={null}
/** Parses and executes the query.
*/
void executeQuery(
    ReadBuffer & istr, /// Where to read the query from (and data for INSERT, if applicable)
    WriteBuffer & ostr, /// Where to write the result
    Context & context, /// DB, tables, data types, engines, functions, aggregate functions...
    BlockInputStreamPtr & query_plan, /// Here could be written the description on how query was executed
    QueryProcessingStage::Enum stage = QueryProcessingStage::Complete /// Up to which stage process the SELECT query
    )
```

**4.** Les commentaires doivent être rédigés en anglais uniquement.

**5.** Si vous écrivez une bibliothèque, incluez dans le fichier d’en-tête principal des commentaires détaillés qui l’expliquent.

**6.** N’ajoutez pas de commentaires qui n’apportent pas d’informations supplémentaires. En particulier, ne laissez pas de commentaires vides comme ceci :

```cpp theme={null}
/*
* Procedure Name:
* Original procedure name:
* Author:
* Date of creation:
* Dates of modification:
* Modification authors:
* Original file name:
* Purpose:
* Intent:
* Designation:
* Classes used:
* Constants:
* Local variables:
* Parameters:
* Date of creation:
* Purpose:
*/
```

L’exemple est tiré de la ressource [http://home.tamk.fi/\~jaalto/course/coding-style/doc/unmaintainable-code/](http://home.tamk.fi/~jaalto/course/coding-style/doc/unmaintainable-code/).

**7.** N’écrivez pas de commentaires superflus (auteur, date de création, etc.) au début de chaque fichier.

**8.** Les commentaires sur une seule ligne commencent par trois barres obliques : `///` et les commentaires sur plusieurs lignes commencent par `/**`. Ces commentaires sont considérés comme de la "documentation".

Remarque : vous pouvez utiliser Doxygen pour générer de la documentation à partir de ces commentaires. Mais Doxygen n’est généralement pas utilisé, car il est plus pratique de parcourir le code dans l’IDE.

**9.** Les commentaires sur plusieurs lignes ne doivent pas comporter de lignes vides au début et à la fin (à l’exception de la ligne qui ferme le commentaire).

**10.** Pour commenter du code, utilisez des commentaires ordinaires, pas des commentaires de "documentation".

**11.** Supprimez les portions de code mises en commentaire avant de valider.

**12.** N’utilisez pas de grossièretés dans les commentaires ou le code.

**13.** N’utilisez pas de majuscules. N’abusez pas de la ponctuation.

```cpp theme={null}
/// WHAT THE FAIL???
```

**14.** N’utilisez pas de commentaires comme délimiteurs.

```cpp theme={null}
///******************************************************
```

**15.** N’engagez pas de discussion dans les commentaires.

```cpp theme={null}
/// Why did you do this stuff?
```

**16.** Il n'est pas nécessaire d'ajouter un commentaire à la fin d'un bloc pour en expliquer le contenu.

```cpp theme={null}
/// for
```

<div id="names">
  ## Noms
</div>

**1.** Utilisez des lettres minuscules et des caractères de soulignement dans les noms de variables et de membres de classe.

```cpp theme={null}
size_t max_block_size;
```

**2.** Pour les noms de fonctions (méthodes), utilisez le camelCase, avec une minuscule initiale.

```cpp theme={null}
std::string getName() const override { return "Memory"; }
```

**3.** Pour les noms de classes (structs), utilisez le CamelCase en commençant par une majuscule. Les interfaces n’utilisent pas de préfixe autre que I.

```cpp theme={null}
class StorageMemory : public IStorage
```

**4.** Les `using` se nomment comme les classes.

**5.** Noms des arguments de type de template : dans les cas simples, utilisez `T` ; `T`, `U` ; `T1`, `T2`.

Pour les cas plus complexes, suivez les règles de nommage des classes ou ajoutez le préfixe `T`.

```cpp theme={null}
template <typename TKey, typename TValue>
struct AggregatedStatElement
```

**6.** Les noms des arguments constants d’un template : soit ils respectent les règles de nommage des variables, soit on utilise `N` dans les cas simples.

```cpp theme={null}
template <bool without_www>
struct ExtractDomain
```

**7.** Pour les classes abstraites (interfaces), vous pouvez ajouter le préfixe `I`.

```cpp theme={null}
class IProcessor
```

**8.** Si vous utilisez une variable localement, vous pouvez lui donner un nom court.

Dans tous les autres cas, utilisez un nom qui décrit clairement ce qu’elle représente.

```cpp theme={null}
bool info_successfully_loaded = false;
```

**9.** Les noms des `define` et des constantes globales s’écrivent en MAJUSCULES avec des traits de soulignement.

```cpp theme={null}
#define MAX_SRC_TABLE_NAMES_TO_STORE 1000
```

**10.** Les noms de fichiers doivent suivre le même style que leur contenu.

Si un fichier contient une seule classe, donnez-lui le même nom que la classe (CamelCase).

Si le fichier contient une seule fonction, donnez-lui le même nom que la fonction (camelCase).

**11.** Si le nom contient une abréviation :

* Pour les noms de variables, l’abréviation doit être en minuscules `mysql_connection` (et non `mySQL_connection`).
* Pour les noms de classes et de fonctions, conservez les majuscules dans l’abréviation `MySQLConnection` (et non `MySqlConnection`).

**12.** Les arguments du constructeur utilisés uniquement pour initialiser les membres de la classe doivent porter le même nom que ces membres, mais avec un trait de soulignement à la fin.

```cpp theme={null}
FileQueueProcessor(
    const std::string & path_,
    const std::string & prefix_,
    std::shared_ptr<FileHandler> handler_)
    : path(path_),
    prefix(prefix_),
    handler(handler_),
    log(&Logger::get("FileQueueProcessor"))
{
}
```

Le suffixe « \_ » peut être omis si l’argument n’est pas utilisé dans le corps du constructeur.

**13.** Il n’y a pas de différence entre les noms des variables locales et ceux des membres de la classe (aucun préfixe n’est requis).

```cpp theme={null}
timer (not m_timer)
```

**14.** Pour les constantes d’un `enum`, utilisez le CamelCase avec une majuscule initiale. ALL\_CAPS est également accepté. Si l’`enum` n’est pas local, utilisez un `enum class`.

```cpp theme={null}
enum class CompressionMethod
{
    QuickLZ = 0,
    LZ4     = 1,
};
```

**15.** Tous les noms doivent être en anglais. La translittération de mots hébreux n'est pas autorisée.

pas T\_PAAMAYIM\_NEKUDOTAYIM

**16.** Les abréviations sont acceptables si elles sont bien connues (si vous pouvez facilement en trouver la signification sur Wikipedia ou dans un moteur de recherche).

`AST`, `SQL`.

Pas `NVDH` (une suite de lettres aléatoires)

Les mots tronqués sont acceptables si la forme abrégée est d'usage courant.

Vous pouvez également utiliser une abréviation si le nom complet figure à côté dans les commentaires.

**17.** Les noms de fichiers de code source C++ doivent avoir l'extension `.cpp`. Les fichiers d'en-tête doivent avoir l'extension `.h`.

<div id="how-to-write-code">
  ## Comment écrire du code
</div>

**1.** Gestion de la mémoire.

La désallocation manuelle de la mémoire (`delete`) ne doit être utilisée que dans le code de bibliothèque.

Dans le code de bibliothèque, l’opérateur `delete` ne doit être utilisé que dans les destructeurs.

Dans le code applicatif, la mémoire doit être libérée par l’objet qui en est propriétaire.

Exemples :

* Le plus simple est de placer un objet sur la pile, ou d’en faire un membre d’une autre classe.
* Pour un grand nombre de petits objets, utilisez des conteneurs.
* Pour désallouer automatiquement un petit nombre d’objets alloués sur le tas, utilisez `shared_ptr/unique_ptr`.

**2.** Gestion des ressources.

Utilisez `RAII` et reportez-vous à ce qui précède.

**3.** Gestion des erreurs.

Utilisez des exceptions. Dans la plupart des cas, il suffit de lever une exception, sans avoir besoin de la capturer (grâce à `RAII`).

Dans les applications de traitement de données hors ligne, il est souvent acceptable de ne pas capturer les exceptions.

Dans les serveurs qui traitent les requêtes des utilisateurs, il suffit généralement de capturer les exceptions au niveau supérieur du gestionnaire de connexion.

Dans les fonctions de thread, vous devez capturer et conserver toutes les exceptions afin de les relancer dans le thread principal après `join`.

```cpp theme={null}
/// If there weren't any calculations yet, calculate the first block synchronously
if (!started)
{
    calculate();
    started = true;
}
else /// If calculations are already in progress, wait for the result
    pool.wait();

if (exception)
    exception->rethrow();
```

Ne masquez jamais les exceptions sans les traiter. Ne consignez jamais aveuglément toutes les exceptions dans les logs.

```cpp theme={null}
//Not correct
catch (...) {}
```

Si vous devez ignorer certaines exceptions, ne le faites que pour des exceptions bien précises et relancez toutes les autres.

```cpp theme={null}
catch (const DB::Exception & e)
{
    if (e.code() == ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION)
        return nullptr;
    else
        throw;
}
```

Lorsque vous utilisez des fonctions avec des codes de réponse ou `errno`, vérifiez toujours le résultat et lancez une exception en cas d’erreur.

```cpp theme={null}
if (0 != close(fd))
    throw ErrnoException(ErrorCodes::CANNOT_CLOSE_FILE, "Cannot close file {}", file_name);
```

Vous pouvez utiliser assert pour vérifier un invariant dans le code.

**4.** Types d’exception.

Il n’est pas nécessaire d’utiliser une hiérarchie d’exceptions complexe dans le code de l’application. Le message de l’exception doit être compréhensible pour un administrateur système.

**5.** Lever des exceptions depuis les destructeurs.

Ce n’est pas recommandé, mais c’est autorisé.

Utilisez les options suivantes :

* Créez une fonction (`done()` ou `finalize()`) qui effectuera à l’avance tout le travail susceptible de provoquer une exception. Si cette fonction a été appelée, il ne devrait plus y avoir d’exception dans le destructeur ensuite.
* Les tâches trop complexes (comme l’envoi de messages sur le réseau) peuvent être placées dans une méthode distincte que l’utilisateur de la classe devra appeler avant la destruction.
* S’il y a une exception dans le destructeur, il vaut mieux l’écrire dans le journal que la masquer (si le logger est disponible).
* Dans les applications simples, il est acceptable de s’appuyer sur `std::terminate` (pour les cas où `noexcept` est utilisé par défaut en C++11) pour gérer les exceptions.

**6.** Blocs de code anonymes.

Vous pouvez créer un bloc de code distinct à l’intérieur d’une même fonction afin de rendre certaines variables locales, de sorte que les destructeurs soient appelés à la sortie du bloc.

```cpp theme={null}
Block block = data.in->read();

{
    std::lock_guard<std::mutex> lock(mutex);
    data.ready = true;
    data.block = block;
}

ready_any.set();
```

**7.** Multithreading.

Dans les programmes de traitement de données hors ligne :

* Essayez d’obtenir les meilleures performances possibles sur un seul cœur de CPU. Vous pourrez ensuite paralléliser votre code si nécessaire.

Dans les applications serveur :

* Utilisez le pool de threads pour traiter les requêtes. Jusqu’à présent, nous n’avons eu aucune tâche nécessitant un changement de contexte en espace utilisateur.

`fork` n’est pas utilisé pour la parallélisation.

**8.** Synchronisation des threads.

Il est souvent possible de faire en sorte que différents threads utilisent des zones mémoire distinctes (mieux encore : des lignes de cache distinctes) et de se passer de toute synchronisation entre threads (à l’exception de `joinAll`).

Si une synchronisation est nécessaire, dans la plupart des cas, il suffit d’utiliser un mutex avec `lock_guard`.

Dans les autres cas, utilisez les primitives de synchronisation du système. N’utilisez pas l’attente active.

Les opérations atomiques ne doivent être utilisées que dans les cas les plus simples.

N’essayez pas d’implémenter des structures de données sans verrou, sauf si c’est votre domaine d’expertise principal.

**9.** Pointeurs ou références.

Dans la plupart des cas, privilégiez les références.

**10.** `const`.

Utilisez des références constantes, des pointeurs vers des constantes, `const_iterator` et des méthodes `const`.

Considérez `const` comme le choix par défaut et n’utilisez le non-`const` que lorsque c’est nécessaire.

Lors du passage de variables par valeur, utiliser `const` n’a généralement pas de sens.

**11.** unsigned.

Utilisez `unsigned` si nécessaire.

**12.** Types numériques.

Utilisez les types `UInt8`, `UInt16`, `UInt32`, `UInt64`, `Int8`, `Int16`, `Int32` et `Int64`, ainsi que `size_t`, `ssize_t` et `ptrdiff_t`.

N'utilisez pas ces types pour représenter des nombres : `signed/unsigned long`, `long long`, `short`, `signed/unsigned char`, `char`.

**13.** Passage d’arguments.

Passez les valeurs complexes par valeur si elles doivent être déplacées, et utilisez `std::move` ; passez-les par référence si vous voulez mettre à jour la valeur dans une boucle.

Si une fonction prend possession d’un objet créé sur le tas, le type de l’argument doit être `shared_ptr` ou `unique_ptr`.

**14.** Valeurs de retour.

Dans la plupart des cas, utilisez simplement `return`. N’écrivez pas `return std::move(res)`.

Si la fonction alloue un objet sur le tas et le renvoie, utilisez `shared_ptr` ou `unique_ptr`.

Dans de rares cas (mise à jour d’une valeur dans une boucle), il peut être nécessaire de renvoyer la valeur via un argument. Dans ce cas, l’argument doit être une référence.

```cpp theme={null}
using AggregateFunctionPtr = std::shared_ptr<IAggregateFunction>;

/** Allows creating an aggregate function by its name.
  */
class AggregateFunctionFactory
{
public:
    AggregateFunctionFactory();
    AggregateFunctionPtr get(const String & name, const DataTypes & argument_types) const;
```

**15.** `namespace`.

Il n'est pas nécessaire d'utiliser un `namespace` distinct pour le code applicatif.

Les petites bibliothèques n'en ont pas non plus besoin.

Pour les bibliothèques de taille moyenne à grande, placez tout dans un `namespace`.

Dans le fichier `.h` de la bibliothèque, vous pouvez utiliser `namespace detail` pour masquer les détails d'implémentation dont le code applicatif n'a pas besoin.

Dans un fichier `.cpp`, vous pouvez utiliser un `namespace` `static` ou anonyme pour masquer des symboles.

De plus, un `namespace` peut être utilisé pour un `enum` afin d'éviter que les noms correspondants ne se retrouvent dans un `namespace` externe (mais il est préférable d'utiliser un `enum class`).

**16.** Initialisation différée.

Si des arguments sont nécessaires pour l'initialisation, il ne faut normalement pas écrire de constructeur par défaut.

Si, plus tard, vous devez retarder l'initialisation, vous pouvez ajouter un constructeur par défaut qui créera un objet invalide. Ou, pour un petit nombre d'objets, vous pouvez utiliser `shared_ptr/unique_ptr`.

```cpp theme={null}
Loader(DB::Connection * connection_, const std::string & query, size_t max_block_size_);

/// For deferred initialization
Loader() {}
```

**17.** Fonctions virtuelles.

Si la classe n'est pas destinée à un usage polymorphique, il n'est pas nécessaire de déclarer les fonctions comme virtuelles. Cela s'applique également au destructeur.

**18.** Encodages.

Utilisez UTF-8 partout. Utilisez `std::string` et `char *`. N'utilisez pas `std::wstring` ni `wchar_t`.

**19.** Journalisation.

Voir les exemples présents partout dans le code.

Avant de valider, supprimez toute journalisation inutile ou de débogage, ainsi que tout autre type de sortie de débogage.

La journalisation dans les boucles doit être évitée, même au niveau Trace.

Les logs doivent être lisibles à tous les niveaux de journalisation.

La journalisation ne devrait, pour l'essentiel, être utilisée que dans le code applicatif.

Les messages de log doivent être rédigés en anglais.

Le log devrait de préférence être compréhensible pour l'administrateur système.

N'utilisez pas de grossièretés dans le log.

Utilisez l'encodage UTF-8 dans le log. Dans de rares cas, vous pouvez y utiliser des caractères non ASCII.

**20.** Entrée-sortie.

N'utilisez pas `iostreams` dans les boucles internes critiques pour les performances de l'application (et n'utilisez jamais `stringstream`).

Utilisez plutôt la bibliothèque `DB/IO`.

**21.** Date et heure.

Voir la bibliothèque `DateLUT`.

**22.** include.

Utilisez toujours `#pragma once` au lieu des gardes d'inclusion.

**23.** using.

`using namespace` ne doit pas être utilisé. Vous pouvez utiliser `using` pour quelque chose de spécifique. Mais limitez-le à une portée locale, à l'intérieur d'une classe ou d'une fonction.

**24.** N'utilisez pas `trailing return type` pour les fonctions, sauf si nécessaire.

```cpp theme={null}
auto f() -> void
```

**25.** Déclaration et initialisation des variables.

```cpp theme={null}
//right way
std::string s = "Hello";
std::string s{"Hello"};

//wrong way
auto s = std::string{"Hello"};
```

**26.** Pour les fonctions virtuelles, écrivez `virtual` dans la classe de base, mais `override` à la place de `virtual` dans les classes dérivées.

<div id="unused-features-of-c">
  ## Éléments de C++ non utilisés
</div>

**1.** L’héritage virtuel n’est pas utilisé.

**2.** Les constructions qui bénéficient d’une syntaxe simplifiée en C++ moderne, par ex.

```cpp theme={null}
// Traditional way without syntactic sugar
template <typename G, typename = std::enable_if_t<std::is_same<G, F>::value, void>> // SFINAE via std::enable_if, usage of ::value
std::pair<int, int> func(const E<G> & e) // explicitly specified return type
{
    if (elements.count(e)) // .count() membership test
    {
        // ...
    }

    elements.erase(
        std::remove_if(
            elements.begin(), elements.end(),
            [&](const auto x){
                return x == 1;
            }),
        elements.end()); // remove-erase idiom

    return std::make_pair(1, 2); // create pair via make_pair()
}

// With syntactic sugar (C++14/17/20)
template <typename G>
requires std::same_v<G, F> // SFINAE via C++20 concept, usage of C++14 template alias
auto func(const E<G> & e) // auto return type (C++14)
{
    if (elements.contains(e)) // C++20 .contains membership test
    {
        // ...
    }

    elements.erase_if(
        elements,
        [&](const auto x){
            return x == 1;
        }); // C++20 std::erase_if

    return {1, 2}; // or: return std::pair(1, 2); // create pair via initialization list or value initialization (C++17)
}
```

<div id="platform">
  ## Plateforme
</div>

**1.** Nous écrivons du code pour une plateforme spécifique.

Mais, toutes choses égales par ailleurs, le code multiplateforme ou portable est préférable.

**2.** Langage : C++20 (voir la liste des [fonctionnalités C++20 disponibles](https://en.cppreference.com/w/cpp/compiler_support#C.2B.2B20_features)).

**3.** Compilateur : `clang`. Au moment de la rédaction (mars 2025), le code est compilé avec clang version >= 19.

La bibliothèque standard est utilisée (`libc++`).

**4.** OS : Ubuntu Linux, version non antérieure à Precise.

**5.** Le code est écrit pour l'architecture CPU x86\_64.

Le jeu d'instructions du CPU correspond au plus petit ensemble pris en charge par nos serveurs. Actuellement, il s'agit de SSE 4.2.

**6.** Utilisez les options de compilation `-Wall -Wextra -Werror -Weverything` avec quelques exceptions.

**7.** Utilisez l'édition de liens statique avec toutes les bibliothèques, sauf celles qu'il est difficile de lier statiquement (voir la sortie de la commande `ldd`).

**8.** Le code est développé et débogué en configuration Release.

<div id="tools">
  ## Outils
</div>

**1.** KDevelop est un bon IDE.

**2.** Pour le débogage, utilisez `gdb`, `valgrind` (`memcheck`), `strace`, `-fsanitize=...` ou `tcmalloc_minimal_debug`.

**3.** Pour le profilage, utilisez `Linux Perf`, `valgrind` (`callgrind`) ou `strace -cf`.

**4.** Le code source est dans Git.

**5.** La compilation utilise `CMake`.

**6.** Les programmes sont publiés sous forme de paquets `deb`.

**7.** Les commits vers master ne doivent pas faire échouer la compilation.

Cependant, seules certaines révisions sont considérées comme exploitables.

**8.** Faites des commits aussi souvent que possible, même si le code n'est que partiellement prêt.

Utilisez des branches à cette fin.

Si votre code dans la branche `master` ne peut pas encore être compilé, excluez-le de la compilation avant le `push`. Vous devrez le terminer ou le supprimer dans les jours qui suivent.

**9.** Pour les modifications non triviales, utilisez des branches et publiez-les sur le serveur.

**10.** Le code inutilisé est supprimé du dépôt.

<div id="libraries">
  ## Bibliothèques
</div>

**1.** La bibliothèque standard C++20 est utilisée (les extensions expérimentales sont autorisées), ainsi que les frameworks `boost` et `Poco`.

**2.** L'utilisation de bibliothèques issues de paquets du système d'exploitation est interdite. L'utilisation de bibliothèques préinstallées l'est également. Toutes les bibliothèques doivent être placées sous forme de code source dans le répertoire `contrib` et compilées avec ClickHouse. Voir [Directives pour l'ajout de nouvelles bibliothèques tierces](/fr/resources/develop-contribute/contribute/contrib#adding-and-maintaining-third-party-libraries) pour plus de détails.

**3.** La préférence est toujours donnée aux bibliothèques déjà utilisées.

<div id="general-recommendations">
  ## Recommandations générales
</div>

**1.** Écrivez le moins de code possible.

**2.** Essayez la solution la plus simple.

**3.** N'écrivez pas de code tant que vous ne savez pas comment il va fonctionner ni comment fonctionnera la boucle interne.

**4.** Dans les cas les plus simples, utilisez `using` plutôt que des classes ou des structs.

**5.** Si possible, n'écrivez ni constructeurs de copie, ni opérateurs d'affectation, ni destructeurs (à l'exception d'un destructeur virtuel, si la classe contient au moins une fonction virtuelle), ni constructeurs de déplacement, ni opérateurs d'affectation par déplacement. En d'autres termes, les fonctions générées par le compilateur doivent fonctionner correctement. Vous pouvez utiliser `default`.

**6.** La simplification du code est encouragée. Réduisez la taille de votre code lorsque c'est possible.

<div id="additional-recommendations">
  ## Recommandations supplémentaires
</div>

**1.** Spécifier explicitement `std::` pour les types de `stddef.h`

n’est pas recommandé. Autrement dit, nous recommandons d’écrire `size_t` plutôt que `std::size_t`, car c’est plus court.

Ajouter `std::` reste acceptable.

**2.** Spécifier explicitement `std::` pour les fonctions de la bibliothèque standard C

n’est pas recommandé. Autrement dit, écrivez `memcpy` plutôt que `std::memcpy`.

La raison est qu’il existe des fonctions non standard similaires, comme `memmem`. Il nous arrive d’utiliser ces fonctions. Elles n’existent pas dans `namespace std`.

Si vous écrivez systématiquement `std::memcpy` au lieu de `memcpy`, alors `memmem` sans `std::` paraîtra étrange.

Néanmoins, vous pouvez quand même utiliser `std::` si vous le préférez.

**3.** Utiliser des fonctions C lorsque les mêmes fonctions sont disponibles dans la bibliothèque standard C++.

C’est acceptable si cela est plus efficace.

Par exemple, utilisez `memcpy` plutôt que `std::copy` pour copier de gros blocs de mémoire.

**4.** Arguments de fonction sur plusieurs lignes.

Tous les styles de retour à la ligne ci-dessous sont autorisés :

```cpp theme={null}
function(
  T1 x1,
  T2 x2)
```

```cpp theme={null}
function(
  size_t left, size_t right,
  const & RangesInDataParts ranges,
  size_t limit)
```

```cpp theme={null}
function(size_t left, size_t right,
  const & RangesInDataParts ranges,
  size_t limit)
```

```cpp theme={null}
function(size_t left, size_t right,
      const & RangesInDataParts ranges,
      size_t limit)
```

```cpp theme={null}
function(
      size_t left,
      size_t right,
      const & RangesInDataParts ranges,
      size_t limit)
```
