Je travaille depuis un bon moment à maintenir un niveau de compatibilité ascendante et descendante dans mes programmes C ++, jusqu'à ce que je devais finalement en faire une boîte à outils de bibliothèque , que je prépare pour la sortie . En général, tant que vous acceptez que vous n'obtiendrez pas de compatibilité ascendante "parfaite" ni dans les fonctionnalités (certaines choses ne peuvent tout simplement pas être émulées vers l'avant) ni dans la syntaxe (vous devrez probablement utiliser des macros, des espaces de noms alternatifs pour certaines choses) alors vous êtes prêt.
De nombreuses fonctionnalités peuvent être émulées en C ++ 03 à un niveau suffisant pour une utilisation pratique - et sans tous les tracas qui accompagnent, par exemple: Boost. Heck, même la proposition de normes C ++ nullptr
suggère un backport C ++ 03. Et puis il y a TR1 par exemple pour tout ce qui est en C ++ 11, mais nous avons eu des aperçus pendant des années. Non seulement cela, certaines fonctionnalités C ++ 14 comme assert des variantes, des foncteurs transparents et optional
peuvent être implémentées en C ++ 03!
Les deux seules choses que je sais qui ne peuvent absolument pas être rétroportées sont les modèles constexpr et variadic.
En ce qui concerne toute la question de l'ajout de choses à l'espace de noms std
, je pense que cela n'a pas d'importance - du tout. Pensez à Boost, l'une des bibliothèques C ++ les plus importantes et pertinentes, et à leur implémentation de TR1: Boost.Tr1. Si vous voulez améliorer C ++, rendez-le compatible avec C ++ 11, puis par définition, vous le transformez en quelque chose qui n'est pas C ++ 03, donc vous bloquer sur une norme que vous avez l'intention d'éviter ou de laisser derrière vous est , tout simplement, contre-productif. Les puristes se plaindront, mais par définition, il ne faut pas s'en soucier.
Bien sûr, ce n'est pas parce que vous ne suivrez pas la norme (03) que vous ne pouvez pas essayer de le faire ou que vous allez joyeusement faire le tour de la briser. Ce n'est pas le propos. Tant que vous gardez un contrôle très attentif sur ce qui est ajouté à l' std
espace de noms et que vous contrôlez les environnements dans lesquels votre logiciel est utilisé (c'est-à-dire: faites des tests!), Il ne devrait y avoir aucun dommage intraitable. Si possible, définissez tout dans un espace de noms séparé et ajoutez uniquement des using
directives à l'espace de noms std
afin de ne rien y ajouter au-delà de ce qui doit "absolument" entrer. Ce qui, IINM, est plus ou moins ce que fait Boost.TR1.
Mise à jour (2013) : comme la demande de la question d'origine et en voyant certains des commentaires que je ne peux pas ajouter en raison du manque de rep, voici une liste des fonctionnalités C ++ 11 et C ++ 14 et leur degré de portabilité en C ++ 03:
nullptr
: pleinement réalisable compte tenu du backport officiel du Comité; vous devrez probablement également fournir certaines spécialisations type_traits afin qu'il soit reconnu comme un type "natif".
forward_list
: entièrement implémentable, bien que le support d'allocateur repose sur ce que votre implication Tr1 peut fournir.
- Nouveaux algorithmes (partition_copy, etc.): entièrement implémentables.
- Constructions de conteneurs à partir de séquences d'accolades (par exemple :)
vector<int> v = {1, 2, 3, 4};
: entièrement implémentables, bien que plus verbeuses que ce que l'on souhaiterait.
static_assert
: presque entièrement implémentable lorsqu'il est implémenté en tant que macro (vous n'aurez qu'à faire attention aux virgules).
unique_ptr
: presque entièrement implémentable, mais vous aurez également besoin de l'aide du code appelant (pour les stocker dans des conteneurs, etc.); voir cependant ci-dessous.
- rvalue-references: presque entièrement implémentable en fonction de ce que vous attendez d'eux (par exemple: Boost Move).
- Pour chaque itération: presque entièrement implémentable, la syntaxe diffère quelque peu.
- utiliser des fonctions locales comme arguments (par exemple: transformer): presque entièrement implémentable, mais la syntaxe sera suffisamment différente - par exemple, les fonctions locales ne sont pas définies sur le site de l'appel mais juste avant.
- opérateurs de conversion explicites: implémentables à des niveaux pratiques (obtenir la conversion explicite), voir "explicit_cast" d' Imperfect C ++ ; mais l'intégration avec des fonctionnalités linguistiques telles que
static_cast<>
pourrait être presque impossible.
- transfert d'argument: implémentable à des niveaux pratiques compte tenu de ce qui précède sur rvalue-references, mais vous devrez fournir N surcharges à vos fonctions en prenant des arguments transmissibles.
- move: implémentable à des niveaux pratiques (voir les deux ci-dessus). Bien sûr, vous devez utiliser des conteneurs et des objets de modification pour en profiter.
- Allocateurs de portée: pas vraiment implémentables à moins que votre implémentation Tr1 puisse les aider.
- types de caractères multi-octets: Pas vraiment implémentable à moins que votre Tr1 ne puisse vous supporter. Mais dans le but prévu, il est préférable de s'appuyer sur une bibliothèque spécialement conçue pour traiter le problème, comme ICU, même si vous utilisez C ++ 11.
- Listes d'arguments variadiques: implémentables avec quelques tracas, faites attention au transfert d'arguments.
noexcept
: dépend des fonctionnalités de votre compilateur.
- De nouvelles
auto
sémantique et decltype
: dépend des caractéristiques de votre compilateur - par exemple .: __typeof__
.
- types entiers de taille (
int16_t
, etc.): dépend des fonctionnalités de votre compilateur - ou vous pouvez déléguer à stdint.h portable.
- Attributs de type: dépend des fonctionnalités de votre compilateur.
- Liste d'initialisation: non réalisable à ma connaissance; cependant, si vous voulez initialiser des conteneurs avec des séquences, voir ci-dessus sur les "constructions de conteneurs".
- Alias de modèle: pas implémentable à ma connaissance, mais c'est une fonctionnalité inutile de toute façon, et nous avons toujours eu des
::type
modèles
- Modèles variadiques: non réalisables à ma connaissance; la fermeture est un argument de modèle par défaut, qui nécessite N spécialisations, etc.
constexpr
: Non réalisable à ma connaissance.
- Initialisation uniforme: Non implémentable à ma connaissance, mais l' initialisation par défaut du constructeur garantie peut être implémentée comme valeur initialisée de Boost.
- C ++ 14
dynarray
: entièrement implémentable.
- C ++ 14
optional<>
: presque entièrement implémentable tant que votre compilateur C ++ 03 prend en charge les configurations d'alignement.
- Foncteurs transparents C ++ 14: presque entièrement implémentables, mais votre code client devra probablement utiliser explicitement par exemple:
std::less<void>
pour le faire fonctionner.
- C ++ 14 nouvelles variantes d'assertion (telles que
assure
): entièrement implémentables si vous voulez des assertions, presque entièrement implémentables si vous souhaitez activer les lancers à la place.
- Extensions de tuple C ++ 14 (obtenir l'élément tuple par type): entièrement implémentable, et vous pouvez même le faire échouer à compiler avec les cas exacts décrits dans la proposition de fonctionnalité.
(Avertissement: plusieurs de ces fonctionnalités sont implémentées dans ma bibliothèque de rétroportages C ++ que j'ai liée ci-dessus, donc je pense que je sais de quoi je parle quand je dis "complètement" ou "presque complètement".)