Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Découvrez comment importer la bibliothèque standard C++ à l’aide de modules de bibliothèque C++. Cela entraîne une compilation plus rapide et est plus robuste que l’utilisation de fichiers d’en-tête ou d’unités d’en-tête ou d’en-têtes précompilés (PCH).
Dans ce tutoriel, découvrez :
- Comment importer la bibliothèque standard en tant que module à partir de la ligne de commande.
- Les avantages en matière de performances et d’utilisation des modules.
- Les deux modules de bibliothèque standard
stdetstd.compatet la différence entre eux.
Prerequisites
Ce tutoriel nécessite Visual Studio 2022 17.5 ou version ultérieure.
Présentation des modules de bibliothèque standard
La sémantique du fichier d’en-tête peut changer en fonction des définitions de macro, de l’ordre dans lequel vous les incluez et de la compilation lente. Les modules résolvent ces problèmes.
Il est désormais possible d’importer la bibliothèque standard en tant que module au lieu d’une tangle de fichiers d’en-tête. Cela est beaucoup plus rapide et plus robuste que d’inclure les fichiers d’en-tête, les unités d’en-tête ou les en-têtes précompilés (PCH).
La bibliothèque standard C++23 introduit deux modules nommés : std et std.compat:
-
stdexporte les déclarations et les noms définis dans l’espace de nomsstdde la bibliothèque standard C++, commestd::vector, par exemple. Il exporte également le contenu des en-têtes wrapper C tels que<cstdio>et<cstdlib>, qui fournissent des fonctions commestd::printf(). Les fonctions C définies dans l’espace de noms global, telles que::printf(), ne sont pas exportées. Cela améliore la situation où l’inclusion d’un en-tête wrapper C comme<cstdio>inclut également des fichiers d’en-tête C commestdio.h, qui apportent les versions de l’espace de noms global C. Ce n’est pas un problème si vous importezstd. -
std.compatexporte tout dansstdet ajoute les espaces de noms globaux du C runtime tels que::printf,::fopen,::size_t,::strlen, etc. Lestd.compatmodule facilite l’utilisation de codebases qui font référence à de nombreuses fonctions/types runtime C dans l’espace de noms global.
Le compilateur importe l’ensemble de la bibliothèque standard lorsque vous utilisez import std; ou import std.compat; le fait plus rapidement que d’apporter un seul fichier d’en-tête. Il est plus rapide d’apporter l’intégralité de la bibliothèque standard avec import std; (ou import std.compat) que pour #include <vector>, par exemple.
Étant donné que les modules nommés n’exposent pas de macros, de macros telles que assert, errno, offsetof, , va_arget d’autres ne sont pas disponibles lorsque vous importez std ou std.compat. Consultez les considérations relatives aux modules nommés de la bibliothèque Standard pour les solutions de contournement.
À propos des modules C++
Les fichiers d’en-tête sont la façon dont les déclarations et les définitions ont été partagées entre les fichiers sources en C++. Avant les modules de bibliothèque standard, vous incluez la partie de la bibliothèque standard dont vous avez besoin avec une directive comme #include <vector>. Les fichiers d’en-tête sont fragiles et difficiles à composer, car leur sémantique peut changer selon l’ordre dans lequel vous les incluez, ou si certaines macros sont définies. Ils ralentissent également la compilation, car ils sont traités par chaque fichier source qui les inclut.
C++20 introduit une alternative moderne appelée modules. En C++23, nous avons pu tirer parti de la prise en charge des modules pour introduire des modules nommés pour représenter la bibliothèque standard.
Comme les fichiers d’en-tête, les modules vous permettent de partager des déclarations et des définitions entre les fichiers sources. Mais contrairement aux fichiers d’en-tête, les modules ne sont pas fragiles et sont plus faciles à composer, car leur sémantique ne change pas en raison de définitions de macros ou de l’ordre dans lequel vous les importez. Le compilateur peut traiter des modules beaucoup plus rapidement qu’il ne peut traiter #include des fichiers et utilise moins de mémoire au moment de la compilation. Les modules nommés n’exposent pas de définitions de macros ni de détails d’implémentation privée.
Cet article illustre la nouvelle et la meilleure façon de consommer la bibliothèque standard. Pour plus d’informations sur les autres façons d’utiliser la bibliothèque standard, consultez Comparer les unités d’en-tête, les modules et les en-têtes précompilés.
Importer la bibliothèque standard avec std
Les exemples suivants montrent comment utiliser la bibliothèque standard en tant que module à l’aide du compilateur de ligne de commande. Pour plus d’informations sur la procédure à suivre dans l’IDE Visual Studio, consultez Générer des modules de bibliothèque ISO C++23 Standard.
L’instruction import std; ou import std.compat; importe la bibliothèque standard dans votre application. Mais tout d’abord, vous devez compiler la bibliothèque standard nommée modules en forme binaire. Les étapes suivantes montrent comment procéder.
Exemple : Comment générer et importer std
Ouvrez une invite de commandes x86 Native Tools pour VS : dans le menu Démarrer de Windows, tapez x86 natif et l’invite doit apparaître dans la liste des applications. Vérifiez que l’invite concerne Visual Studio 2022 version 17.5 ou ultérieure. Vous obtenez des erreurs si vous utilisez la version incorrecte de l’invite. Les exemples utilisés dans ce didacticiel concernent l’interpréteur de commandes CMD.
Créez un répertoire, tel que
%USERPROFILE%\source\repos\STLModules, et définissez-le comme répertoire actif. Si vous choisissez un répertoire auquel vous n’avez pas accès en écriture, vous obtiendrez des erreurs lors de la compilation.Compilez le
stdmodule nommé avec la commande suivante :cl /std:c++latest /EHsc /nologo /W4 /c "%VCToolsInstallDir%\modules\std.ixx"Si vous recevez des erreurs, vérifiez que vous utilisez la version correcte de l’invite de commandes.
Compilez le
stdmodule nommé à l’aide des mêmes paramètres de compilateur que celui que vous envisagez d’utiliser avec le code qui importe le module généré. Si vous disposez d’une solution multi-projet, vous pouvez compiler le module nommé de bibliothèque standard une seule fois, puis vous y référer à partir de tous vos projets à l’aide de l’option/referencedu compilateur.À l’aide de la commande du compilateur précédente, le compilateur génère deux fichiers :
-
std.ifcest la représentation binaire compilée de l’interface de module nommée que le compilateur consulte pour traiter l’instructionimport std;. Il s’agit d’un artefact au moment de la compilation uniquement. Il n’est pas fourni avec votre application. -
std.objcontient l’implémentation du module nommé. Ajoutezstd.objà la ligne de commande lorsque vous compilez l’exemple d’application pour lier statiquement les fonctionnalités que vous utilisez de la bibliothèque standard à votre application.
Les commutateurs de ligne de commande clés dans cet exemple sont les suivants :
Interrupteur Meaning /std:c++latestUtilisez la dernière version du langage C++ standard et de la bibliothèque. Bien que la prise en charge des modules soit disponible sous /std:c++20, vous avez besoin du dernier standard de bibliothèque pour obtenir la prise en charge des modules de la bibliothèque standard nommés./EHscUtilisez la gestion des exceptions C++, à l’exception des fonctions marquées extern "C"./W4L’utilisation /W4est généralement recommandée, en particulier pour les nouveaux projets, car elle active tous les avertissements de niveau 1, de niveau 2, de niveau 3 et de la plupart des avertissements de niveau 4 (informations), ce qui peut vous aider à détecter les problèmes potentiels au début. Il fournit essentiellement des avertissements de type lint qui peuvent aider à réduire autant que possible les défauts de code difficiles à détecter./cCompilez sans liaison, car nous créons simplement l’interface de module nommée binaire à ce stade. Vous pouvez contrôler le nom du fichier objet et le nom du fichier d’interface de module nommé avec les commutateurs suivants :
-
/Fodéfinit le nom du fichier objet. Par exemple :/Fo:"somethingelse". Par défaut, le compilateur utilise le même nom pour le fichier objet que le fichier source du module (.ixx) que vous compilez. Dans l’exemple, le nom du fichier objet eststd.objpar défaut, car nous compilez le fichier destd.ixxmodule. -
/ifcOutputdéfinit le nom du fichier d’interface du module nommé (.ifc). Par exemple :/ifcOutput "somethingelse.ifc". Par défaut, le compilateur utilise le même nom pour le fichier d’interface du module (.ifc) que le fichier source du module (.ixx) que vous compilez. Dans l’exemple, le fichier généréifceststd.ifcpar défaut, car nous compileons le fichier destd.ixxmodule.
-
Importez la
stdbibliothèque que vous avez créée en créant d’abord un fichier nomméimportExample.cppavec le contenu suivant :// requires /std:c++latest import std; int main() { std::cout << "Import the STL library for best performance\n"; std::vector<int> v{5, 5, 5}; for (const auto& e : v) { std::cout << e; } }Dans le code précédent,
import std;remplace#include <vector>et#include <iostream>. L’instructionimport std;rend toutes les bibliothèques standard disponibles avec une seule instruction. L’importation de l’ensemble de la bibliothèque standard est souvent beaucoup plus rapide que le traitement d’un seul fichier d’en-tête de bibliothèque standard tel que#include <vector>.Compilez l’exemple à l’aide de la commande suivante dans le même répertoire que l’étape précédente :
cl /c /std:c++latest /EHsc /nologo /W4 /reference "std=std.ifc" importExample.cpp link importExample.obj std.objIl n’est pas nécessaire de spécifier
/reference "std=std.ifc"sur la ligne de commande de cet exemple, car le compilateur recherche automatiquement le fichier correspondant au.ifcnom du module spécifié par l’instructionimport. Lorsque le compilateur rencontreimport std;, il peut trouverstd.ifcs’il se trouve dans le même répertoire que le code source. Si le.ifcfichier se trouve dans un répertoire différent du code source, utilisez le/referencecommutateur du compilateur pour y faire référence.Dans cet exemple, la compilation du code source et la liaison de l’implémentation du module dans l’application sont des étapes distinctes. Ils n’ont pas besoin d’être. Vous pouvez utiliser
cl /std:c++latest /EHsc /nologo /W4 /reference "std=std.ifc" importExample.cpp std.objpour compiler et lier en une seule étape. Toutefois, il peut être pratique de créer et de lier séparément, car vous devez uniquement générer le module nommé de la bibliothèque standard une seule fois, puis vous pouvez y faire référence à partir de votre projet, ou à partir de plusieurs projets, à l’étape de lien de votre build.Si vous créez un projet unique, vous pouvez combiner les étapes de création
stddu module nommé bibliothèque standard et de l’étape de création de votre application en ajoutant"%VCToolsInstallDir%\modules\std.ixx"à la ligne de commande. Placez-le avant les.cppfichiers qui consomment lestdmodule.Par défaut, le nom de l’exécutable de sortie est extrait du premier fichier d’entrée. Utilisez l’option du
/Fecompilateur pour spécifier le nom de fichier exécutable souhaité. Ce tutoriel montre la compilation dustdmodule nommé en tant qu’étape distincte, car vous devez uniquement générer le module nommé de bibliothèque standard une seule fois, puis vous pouvez y faire référence à partir de votre projet ou à partir de plusieurs projets. Toutefois, il peut être pratique de créer tout ensemble, comme illustré par cette ligne de commande :cl /FeimportExample /std:c++latest /EHsc /nologo /W4 "%VCToolsInstallDir%\modules\std.ixx" importExample.cppCompte tenu de la ligne de commande précédente, le compilateur produit un exécutable nommé
importExample.exe. Lorsque vous l’exécutez, elle produit la sortie suivante :Import the STL library for best performance 555
Importer la bibliothèque standard et les fonctions C globales avec std.compat
La bibliothèque standard C++ inclut la bibliothèque standard ISO C. Le std.compat module fournit toutes les fonctionnalités du std module comme std::vector, , std::coutstd::printf, std::scanf, et ainsi de suite. Mais il fournit également les versions d’espace de noms globales de ces fonctions telles que ::printf, ::scanf, ::fopen, ::size_t, etc.
Le std.compat module nommé est une couche de compatibilité fournie pour faciliter la migration du code existant qui fait référence aux fonctions runtime C dans l’espace de noms global. Si vous souhaitez éviter d’ajouter des noms à l’espace de noms global, utilisez import std;. Si vous devez faciliter la migration d’une base de code qui utilise de nombreuses fonctions runtime C non qualifiées (espace de noms global), utilisez import std.compat;. Ceci fournit les noms d'exécution C de l'espace de noms global afin que vous n'ayez pas à qualifier tous les noms globaux avec std::. Si vous n’avez pas de code existant qui utilise les fonctions d’exécution C de l’espace de noms global, vous n’avez pas besoin d’utiliser import std.compat;. Si vous n'appelez que quelques fonctions de runtime C dans votre code, il peut être préférable d'utiliser import std; et de qualifier avec std:: les quelques noms de runtime C du namespace global qui en ont besoin. Par exemple : std::printf(). Si vous voyez une erreur comme error C3861: 'printf': identifier not found lorsque vous essayez de compiler votre code, envisagez d'utiliser import std.compat; pour importer les fonctions runtime C de l'espace de noms global.
Exemple : Comment générer et importer std.compat
Avant de pouvoir utiliser import std.compat; , vous devez compiler le fichier d’interface de module trouvé dans le formulaire de code source dans std.compat.ixx. Visual Studio fournit le code source du module afin de pouvoir compiler le module à l’aide des paramètres du compilateur qui correspondent à votre projet. Les étapes sont similaires à la création du std module nommé. Le std module nommé est créé en premier, car std.compat dépend de celui-ci :
Ouvrez une invite de commandes Native Tools pour VS : dans le menu Démarrer de Windows, tapez x86 natif et l’invite doit apparaître dans la liste des applications. Vérifiez que l’invite concerne Visual Studio 2022 version 17.5 ou ultérieure. Vous obtiendrez des erreurs de compilation si vous utilisez la version incorrecte de l’invite.
Créez un répertoire pour essayer cet exemple, tel que
%USERPROFILE%\source\repos\STLModules, et définissez-le comme répertoire courant. Si vous choisissez un répertoire auquel vous n’avez pas accès en écriture, vous obtiendrez des erreurs.Compilez les modules
stdetstd.compatnommés avec la commande suivante :cl /std:c++latest /EHsc /nologo /W4 /c "%VCToolsInstallDir%\modules\std.ixx" "%VCToolsInstallDir%\modules\std.compat.ixx"Vous devez compiler
stdetstd.compatutiliser les mêmes paramètres de compilateur que ceux que vous envisagez d’utiliser avec le code qui les importera. Si vous avez une solution multi-projet, vous pouvez les compiler une seule fois, puis les référencer à partir de tous vos projets à l’aide de l’option du/referencecompilateur.Si vous recevez des erreurs, vérifiez que vous utilisez la version correcte de l’invite de commandes.
Le compilateur génère quatre fichiers des deux étapes précédentes :
-
std.ifcest l’interface de module nommée binaire compilée que le compilateur consulte pour traiter l’instructionimport std;. Le compilateur consultestd.ifcégalement pour traiterimport std.compat;, carstd.compats’appuie surstd. Il s’agit d’un artefact au moment de la compilation uniquement. Il n’est pas fourni avec votre application. -
std.objcontient l’implémentation de la bibliothèque standard. -
std.compat.ifcest l’interface de module nommée binaire compilée que le compilateur consulte pour traiter l’instructionimport std.compat;. Il s’agit d’un artefact au moment de la compilation uniquement. Il n’est pas fourni avec votre application. -
std.compat.objcontient l’implémentation. Toutefois, la plupart de l’implémentation est fournie parstd.obj. Ajoutezstd.objà la ligne de commande lorsque vous compilez l'exemple d’application afin de lier statiquement les fonctionnalités que vous utilisez de la bibliothèque standard à votre application.
Vous pouvez contrôler le nom du fichier objet et le nom du fichier d’interface de module nommé avec les commutateurs suivants :
-
/Fodéfinit le nom du fichier objet. Par exemple :/Fo:"somethingelse". Par défaut, le compilateur utilise le même nom pour le fichier objet que le fichier source du module (.ixx) que vous compilez. Dans l’exemple, les noms des fichiers objet sontstd.objetstd.compat.objpar défaut, car nous compilez les fichiersstd.ixxde module etstd.compat.ixx. -
/ifcOutputdéfinit le nom du fichier d’interface du module nommé (.ifc). Par exemple :/ifcOutput "somethingelse.ifc". Par défaut, le compilateur utilise le même nom pour le fichier d’interface du module (.ifc) que le fichier source du module (.ixx) que vous compilez. Dans l’exemple, les fichiers générésifcsontstd.ifcetstd.compat.ifcpar défaut, car nous compilez les fichiersstd.ixxde module etstd.compat.ixx.
-
Importez la
std.compatbibliothèque en créant d’abord un fichier nomméstdCompatExample.cppavec le contenu suivant :import std.compat; int main() { printf("Import std.compat to get global names like printf()\n"); std::vector<int> v{5, 5, 5}; for (const auto& e : v) { printf("%i", e); } }Dans le code précédent,
import std.compat;remplace#include <cstdio>et#include <vector>. L’instructionimport std.compat;rend la bibliothèque standard et les fonctions runtime C disponibles avec une instruction. L’importation de ce module nommé, qui inclut la bibliothèque standard C++ et les fonctions d’espace de noms globaux de la bibliothèque runtime C, est plus rapide que le traitement d’un seul#includetype#include <vector>.Compilez l’exemple à l’aide de la commande suivante :
cl /std:c++latest /EHsc /nologo /W4 stdCompatExample.cpp link stdCompatExample.obj std.obj std.compat.objNous n’avons pas dû spécifier
std.compat.ifcsur la ligne de commande, car le compilateur recherche automatiquement le.ifcfichier qui correspond au nom du module dans uneimportinstruction. Lorsque le compilateur rencontreimport std.compat;, il trouvestd.compat.ifcpuisque nous l'avons placé dans le même répertoire que le code source, ce qui nous évite de devoir le spécifier sur la ligne de commande. Si le.ifcfichier se trouve dans un répertoire différent du code source ou a un nom différent, utilisez le commutateur du/referencecompilateur pour y faire référence.Lorsque vous importez
std.compat, vous devez établir un lien entre les deuxstd.compatetstd.objparce qu’ilstd.compatutilise du code dansstd.obj.Si vous créez un projet unique, vous pouvez combiner les étapes de construction du module
stdet des modules nommés de la bibliothèque standardstd.compaten ajoutant"%VCToolsInstallDir%\modules\std.ixx"et"%VCToolsInstallDir%\modules\std.compat.ixx"(dans cet ordre) à la ligne de commande. Ce tutoriel montre comment créer les modules de bibliothèque standard en tant qu’étape distincte, car vous devez uniquement générer les modules nommés par la bibliothèque standard une seule fois, puis vous pouvez les référencer à partir de votre projet ou à partir de plusieurs projets. Toutefois, s’il est pratique de les générer tous en même temps, veillez à les placer avant les.cppfichiers qui les consomment et spécifiez de nommer/Fele fichier généréexecomme illustré dans cet exemple :cl /c /FestdCompatExample /std:c++latest /EHsc /nologo /W4 "%VCToolsInstallDir%\modules\std.ixx" "%VCToolsInstallDir%\modules\std.compat.ixx" stdCompatExample.cpp link stdCompatExample.obj std.obj std.compat.objDans cet exemple, la compilation du code source et la liaison de l’implémentation du module dans votre application sont des étapes distinctes. Ils n’ont pas besoin d’être. Vous pouvez utiliser
cl /std:c++latest /EHsc /nologo /W4 stdCompatExample.cpp std.obj std.compat.objpour compiler et lier en une seule étape. Toutefois, il peut être pratique de créer et de lier séparément, car vous devez uniquement générer les modules nommés par la bibliothèque standard une seule fois, puis vous pouvez les référencer à partir de votre projet, ou à partir de plusieurs projets, à l’étape de lien de votre build.La commande du compilateur précédente produit un exécutable nommé
stdCompatExample.exe. Lorsque vous l’exécutez, elle produit la sortie suivante :Import std.compat to get global names like printf() 555
Considérations relatives aux modules nommés de la bibliothèque standard
Le contrôle de version pour les modules nommés est le même que pour les en-têtes. Les fichiers de module nommés .ixx sont installés en parallèle avec les en-têtes, par exemple : "%VCToolsInstallDir%\modules\std.ixx", ce qui correspond à C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.38.33130\modules\std.ixx dans la version des outils utilisée au moment de la rédaction. Sélectionnez la version du module nommé de la même façon que vous choisissez la version du fichier d’en-tête à utiliser par le répertoire à partir duquel vous faites référence.
Ne mélangez pas l'importation de fichiers d'en-tête et de modules nommés. Par exemple, n'utilisez pas import <vector>; et import std; dans le même fichier.
Ne mélangez pas l’importation de fichiers d’en-tête de la bibliothèque standard C++ avec les modules nommés std ou std.compat. Par exemple, ne pas utiliser #include <vector> et import std; dans le même fichier. Toutefois, vous pouvez inclure des en-têtes C et importer des modules nommés dans le même fichier. Par exemple, vous pouvez import std; et #include <math.h> dans le même fichier. N’incluez pas la version <cmath>de la bibliothèque standard C++.
Vous n’avez pas à vous défendre contre l’importation d’un module plusieurs fois. Autrement dit, vous n’avez pas besoin de gardes d’en-tête de style #ifndef dans les modules. Le compilateur sait quand il a déjà importé un module nommé et ignore les tentatives répétitives de le faire.
Si vous devez utiliser la assert() macro, puis #include <assert.h>.
Si vous devez utiliser la errno macro, #include <errno.h>. Étant donné que les modules nommés n’exposent pas de macros, il s’agit de la solution de contournement si vous devez vérifier les erreurs à partir de <math.h>, par exemple.
Les macros telles que NAN, INFINITYet INT_MIN sont définies par <limits.h>, que vous pouvez inclure. Toutefois, si vous pouvez utiliser std::numeric_limits<double>::quiet_NaN() et std::numeric_limits<double>::infinity() au lieu de NAN et INFINITY, et std::numeric_limits<int>::min() plutôt que INT_MIN.
Résumé
Dans ce tutoriel, vous avez importé la bibliothèque standard à l’aide de modules. Découvrez ensuite comment créer et importer vos propres modules dans le didacticiel sur les modules nommés en C++.
Voir aussi
Comparer les unités d’en-tête, les modules et les en-têtes précompilés
Vue d’ensemble des modules en C++
Visite guidée des modules C++ dans Visual Studio
Déplacement d’un projet vers des modules nommés C++