2024-01-22 13:39:00
Bien que Peter Gottschling ait écrit deux excellents articles de blog sur la bibliothèque de formatage en C++20 (“std::format en C++20”, “C++20 : extension de std::format avec des types de données définis par l’utilisateur”) , je vais y revenir en écrivant la bibliothèque de formatage. La raison en est simple : l’article de Peter fournit une excellente introduction et un bon aperçu. Je voudrais présenter tous les détails afin que chacun puisse utiliser cet article et les articles à venir comme guide de référence.
Publicité
Rainer Grimm travaille depuis de nombreuses années en tant qu’architecte logiciel, responsable d’équipe et de formation. Il aime écrire des articles sur les langages de programmation C++, Python et Haskell, mais aime également intervenir fréquemment lors de conférences spécialisées. Sur son blog Modern C++, il parle intensément de sa passion C++.
C++20 prend en charge les fonctionnalités de formatage suivantes :
Les fonctions std::format
et std::format_to
sont fonctionnellement équivalents à leurs homologues std::vformat
et std::vformat_to
mais ils diffèrent de plusieurs manières :
std::format, std::_format_to
etstd::format_to_n
: Vous avez besoin d’une valeur sous forme de chaîne de format au moment de la compilation. Cette chaîne de format peut être unconstexpr
-String ou une chaîne littérale.std::vformat
etstd::vformat_t:
La chaîne de format peut être une lValue. Les arguments doivent aller à la fonction variadiquestd::make_format_args
être transmis, par exemple :std::vformat(formatString, std::make_format_args(args))
.
Les fonctions de formatage acceptent n’importe quel nombre d’arguments. Le programme suivant donne une première impression des fonctions std::format
, std::format_to
et std::format_to_n
.
// format.cpp
#include
#include
#include
#include
int main() {
std::cout << 'n';
std::cout << std::format("Hello, C++{}!n", "20")
<< 'n'; // (1)
std::string buffer;
std::format_to( // (2)
std::back_inserter(buffer),
"Hello, C++{}!n",
"20");
std::cout << buffer << 'n';
buffer.clear();
std::format_to_n( // (3)
std::back_inserter(buffer), 5,
"Hello, C++{}!n",
"20");
std::cout << buffer << 'n';
std::cout << 'n';
}
Le programme affiche directement la chaîne de caractères formatée en (1). Cependant, les appels en (2) et (3) utilisent une chaîne comme tampon. Pousse également std::format_to_n
seulement cinq caractères dans le tampon.
Voici donc le programme correspondant qui std::vformat
et std::vformat_n
utilisé:
// formatRuntime.cpp
#include
#include
#include
#include
int main() {
std::cout << 'n';
std::string formatString = "Hello, C++{}!n";
std::cout << std::vformat(formatString,
std::make_format_args("20"))
<< 'n'; // (1)
std::string buffer;
std::vformat_to( // (2)
std::back_inserter(buffer),
formatString,
std::make_format_args("20"));
std::cout << buffer << 'n';
}
Le formatString
dans (1) et (2) est une lValue.
La partie la plus intéressante des fonctions de formatage est probablement la chaîne de format ("Hallo, C++{}!n"
).
Chaîne de formatage
La syntaxe de la chaîne de format est dans les fonctions de formatage std::format,
std::format_to, std::format_to_n, std::vformat
et std::vformat_to
identique. j'utilise std::format
dans mes exemples.
- Syntaxe: std :: format (FormatString, Args)
Il y a le formatage FormatString
consiste
- Caractères ordinaires (sauf { et }),
- Séquences d'échappement {{ et }}, qui sont également remplacées par { et }
- champs de remplacement.
Un champ de remplacement a le format { }.
- Vous pouvez utiliser un ID d'argument et deux points dans le champ de remplacement, suivis d'une spécification de format. Les deux composants sont facultatifs.
L'ID d'argument peut être utilisé pour obtenir l'index des arguments dans Args
indiquer. Les ID commencent par 0. Si aucun ID d'argument n'est spécifié, les champs sont renseignés dans le même ordre dans lequel les arguments sont spécifiés. Soit tous les champs de remplacement doivent utiliser un ID d'argument, soit aucun ; Cela signifie std::format("{}, {}", "Hallo", "Welt")
et std::format("{1}, {0}", "Welt", "Hallo")
Les deux sont compilés, mais std::format("{1}, {}", "Welt", "Hallo")
pas.
std::formatter
et ses spécialisations définissent la spécification de format pour les types d'arguments.
- Types de données de base et
std::string
: sont basés sur la spécification du format Python. - Types de chrono : je les présenterai dans un des prochains articles.
- Autres types de données formatables : personnalisé
std::formatter
-Spécialisation. Je les présenterai dans un autre article.
Le fait que les chaînes de format soient une variable à la compilation a deux conséquences intéressantes : les performances et la sécurité.
Temps de compilation
- Performances : si la chaîne de format est vérifiée au moment de la compilation, rien ne doit être fait au moment de l'exécution. Par conséquent, les trois fonctions promettent
std::format, std::format_to
etstd::format_to_n
une excellente prestation. La bibliothèque de prototypes fmt a des repères passionnants. - Sécurité : L'utilisation d'une chaîne de format incorrecte au moment de la compilation entraînera une erreur de compilation. En revanche, en utilisant une chaîne de format au moment de l'exécution
std::vformat
oustd::vformat_to
à unstd::format_error
-Exception.
Et après?
Dans le prochain article du blog, je compléterai la théorie par la pratique.
(moi)
#Développement #logiciel #bibliothèque #formatage #C20
1705924496