
Au lieu de l'avant-propos
Peut-être qu'avec cette image, toute histoire de
boost ,
Loki , indépendant, ainsi que les implémentations de la bibliothèque C ++ standard fournie avec les compilateurs devraient commencer.
Oui, oui, et si vous pensiez que les développeurs de la bibliothèque standard pour le même g ++, clang, Visual Studio ou, Dieu me pardonne, C ++ Builder (anciennement Borland, mais l'actuel Embarcadero) sont des gourous qui ne font pas de béquilles, ils ne cassent pas la norme pour leur compilateur et n'écrivez pas de vélos, alors vous n'utilisez probablement pas aussi activement la bibliothèque C ++ standard que vous le pensiez.
L'article est écrit comme une histoire et contient beaucoup «d'eau» et de digressions, mais j'espère que mon expérience et le code résultant seront utiles à ceux qui ont rencontré des problèmes similaires lors du développement en C ++, en particulier sur les anciens compilateurs. Lien vers GitHub avec le résultat d'aujourd'hui pour les impatients et les non-lecteurs:
https://github.com/oktonion/stdex (les commits et les critiques constructives sont les bienvenus)
Et maintenant, tout d'abord.
Table des matières
Présentation
Chapitre 1. Viam supervadet vadensChapitre 2. #ifndef __CPP11_SUPPORT__ #define __COMPILER_SPECIFIC_BUILT_IN_AND_MACRO_HELL__ #endifChapitre 3. Recherche de l'implémentation nullptr parfaiteChapitre 4. Magie des modèles C ++....
4.1 On commence petit....
4.2 À propos du nombre d'erreurs miraculeuses que le journal compile pour nous....
4.3 Pointeurs et tout-tout....
4.4 Quoi d'autre est nécessaire pour la bibliothèque de modèlesChapitre 5
...
Entrée
C'était en 2017, C ++ 11 a depuis longtemps fait irruption dans un nouveau flux de compilateurs nouveaux et relativement nouveaux, apportant un travail standardisé avec des flux, des mutex, en élargissant la programmation de modèles et en standardisant les approches, il existe enfin de «grands» types
longs et longs dans la norme , enfin s'est débarrassé du besoin généralisé d'afficher les types du compilateur en utilisant
auto (au revoir
std :: map <type, type> :: const_iterator it = ... - eh bien, vous me comprenez), et la combinaison de cette fonctionnalité avec la nouvelle
pour chacun est devenue l'une des plus courantes implémentations d'itérateur de boucle utilisées. Enfin, nous (développeurs) avons pu expliquer humainement à l'utilisateur (développeur) pourquoi le code n'est pas collecté à l'aide de
static_assert , ainsi que
enable_if , qui sélectionne désormais les surcharges nécessaires comme par magie.
Dans la cour était 2017! Déjà C ++ 17 était activement introduit dans GCC, clang, Visual Studio, partout où il y avait
decltype (depuis C ++ 11),
constexpr (depuis C ++ 11, mais significativement amélioré), les modules étaient presque en route, il y avait un bon moment. J'étais au travail et avec une certaine désapprobation, j'ai regardé la prochaine erreur de compilation interne dans mon Borland C ++ Builder 6.0, ainsi que de nombreuses erreurs de construction avec la prochaine version de la bibliothèque de boost. Je pense que vous comprenez maintenant d'où vient cette envie de construire des vélos. Nous avons utilisé Borland C ++ Builder 6.0 et Visual Studio 2010 pour Windows, g ++ version 4.4.2 ou inférieure pour
QNX et pour certains systèmes Unix. Nous avons été épargnés de MacOS, ce qui était sans aucun doute un avantage. Aucun autre compilateur (y compris C ++ 11) n'a même pu être envisagé pour des raisons que nous laissons en dehors de cet article.
"Et ce qui pourrait être si compliqué là-bas" - une pensée s'est glissée dans mes tentatives épuisées de faire un boost sous le bon vieux cerveau de constructeur. "Tout ce dont j'ai besoin est de
type_traits ,
thread ,
mutex , peut-être
chrono ,
nullptr serait bien." J'ai raisonné et je me suis mis au travail.
Chapitre 1. Viam supervadet vadens
Il était nécessaire de commencer par où et par où - naturellement j'avais un certain nombre de fichiers d'en-tête et de codes source dispersés à travers les projets avec des implémentations de fonctionnalités similaires ou identiques de la bibliothèque standard C ++ 11 standard de mon développement, ainsi que honnêtement empruntés ou traités à partir des codes de ce même gcc et boost. En combinant tout cela, j'ai eu un désordre de fonctions, de classes, de macros qui était censé se transformer en une bibliothèque standard élégante et élancée. Ayant estimé la quantité de travail, j'ai immédiatement décidé d'abandonner l'implémentation de tout et de tout, me limitant au développement d'un «add-on» sur la bibliothèque C ++ 98 standard fournie avec le compilateur.
Dans la version initiale, il n'y avait pas d'adhésion particulière à la norme, principalement les problèmes appliqués ont été résolus. Par exemple,
nullptr ressemblait à ceci:
#define nullptr 0
static_assert a également été résolu simplement:
#define STATIC_ASSERT(expr) typedef int test##__LINE__##[expr ? 1 : -1];
std :: to_string a été implémenté via
std :: stringstream , qui a été remplacé par
std :: strstream dans les implémentations sans le fichier d'en-tête
sstream , et tout cela a été immédiatement inséré dans l'
espace de noms std :
#ifndef NO_STD_SSTREAM_HEADER #include <sstream> #else #include <strstream> namespace std {typedef std::strstream stringstream;} #endif namespace std { template<class T> string to_string(const T &t) { stringstream ss; ss << t; return ss.str(); } }
Il y avait aussi des «trucs» qui n'étaient pas inclus dans la norme, mais néanmoins utiles dans le travail de tous les jours, comme les
macros forever ou
countof :
#define forever for(;;)
countof est ensuite transformé en une option plus C ++:
template <typename T, std::size_t N> char(&COUNTOF_REQUIRES_ARRAY_ARGUMENT(T(&)[N]))[N];
Le travail avec les threads (le
thread du fichier d'en-tête de std) a été implémenté via certaines des bibliothèques Tiny, réécrites en tenant compte des fonctionnalités de l'ensemble du zoo des compilateurs et du système d'exploitation. Et peut-être que
type_traits était dans une certaine mesure déjà similaire à ce que la norme C ++ 11. exigeait
: std :: enable_if ,
std :: integrale_constant ,
std :: is_const et les modèles similaires déjà utilisés dans le développement.
namespace std { template<bool Cond, class Iftrue, class Iffalse> struct conditional { typedef Iftrue type; };
Il a été décidé de séparer toutes les macros, fonctions et types non standard et "compilateur" dans un fichier d'en-tête
core.h. Et, contrairement à la pratique du boost, où la "commutation" d'implémentations utilisant des macros est largement utilisée, abandonner les macros liées aux choses
dépendantes du compilateur dans tous les fichiers de bibliothèque, sauf
core.h. De plus, la fonctionnalité qui ne peut pas être implémentée sans l'utilisation de «hacks» (violation de la norme, s'appuyant sur un comportement non défini pour être quelque peu défini), ou est implémentée individuellement pour chaque compilateur (par le biais de ses macros intégrées, par exemple), il a été décidé de ne pas l'ajouter à la bibliothèque, afin de ne pas produire un autre boost monstrueux (mais beau). Par conséquent, la principale et pratiquement la seule chose pour laquelle
core.h est utilisé est de déterminer s'il existe une prise en charge pour
nullptr intégré (car les compilateurs jurent en cas de substitution des mots réservés), la prise en
charge de
static_assert intégré (encore une fois, pour éviter de croiser un mot réservé) et la prise en charge des types intégrés C ++ 11
char16_t et
char32_t .
Pour l'avenir, je peux dire que l'idée a été presque un succès, car la plupart de ce qui est défini dans boost par des macros dures en fonction d'un compilateur particulier, dans cette implémentation est déterminé par le compilateur lui-même au stade de la compilation.
La fin du premier chapitre. Dans le
deuxième chapitre, je continuerai la narration sur les difficultés de traiter avec les compilateurs, sur les béquilles trouvées et les solutions élégantes dans les entrailles de gcc, boost et Visual Studio, ainsi qu'une description de mes impressions de ce que j'ai vu et acquis de l'expérience avec des exemples de code.
Merci de votre attention.