Il y a deux parties à la réponse. Compatibilité au niveau du compilateur et compatibilité au niveau de l'éditeur de liens. Commençons par le premier.
supposons que tous les en-têtes ont été écrits en C ++ 11
L'utilisation du même compilateur signifie que le même en-tête de bibliothèque standard et les mêmes fichiers source (les onces associés au compilateur) seront utilisés quel que soit le standard C ++ cible. Par conséquent, les fichiers d'en-tête de la bibliothèque standard sont écrits pour être compatibles avec toutes les versions C ++ prises en charge par le compilateur.
Cela dit, si les options du compilateur utilisées pour compiler une unité de traduction spécifient une norme C ++ particulière, alors toutes les fonctionnalités qui ne sont disponibles que dans les normes plus récentes ne devraient pas être accessibles. Ceci est fait en utilisant la __cplusplus
directive. Voir le fichier source vectoriel pour un exemple intéressant de la façon dont il est utilisé. De même, le compilateur rejettera toutes les fonctionnalités syntaxiques offertes par les nouvelles versions de la norme.
Tout cela signifie que votre hypothèse ne peut s'appliquer qu'aux fichiers d'en-tête que vous avez écrits. Ces fichiers d'en-tête peuvent provoquer des incompatibilités lorsqu'ils sont inclus dans différentes unités de traduction ciblant différentes normes C ++. Ceci est discuté dans l'annexe C de la norme C ++. Il y a 4 articles, je ne parlerai que du premier et je mentionnerai brièvement le reste.
C.3.1 Clause 2: conventions lexicales
Les guillemets simples délimitent un littéral de caractère en C ++ 11, alors qu'ils sont des séparateurs de chiffres en C ++ 14 et C ++ 17. Supposons que vous ayez la définition de macro suivante dans l'un des fichiers d'en-tête C ++ 11 purs:
#define M(x, ...) __VA_ARGS__
// Maybe defined as a field in a template or a type.
int x[2] = { M(1'2,3'4) };
Considérez deux unités de traduction qui incluent le fichier d'en-tête, mais ciblent respectivement C ++ 11 et C ++ 14. Lorsque vous ciblez C ++ 11, la virgule entre guillemets n'est pas considérée comme un séparateur de paramètres; il n'y a qu'un seul paramètre. Par conséquent, le code serait équivalent à:
int x[2] = { 0 }; // C++11
En revanche, lorsque vous ciblez C ++ 14, les guillemets simples sont interprétés comme des séparateurs de chiffres. Par conséquent, le code serait équivalent à:
int x[2] = { 34, 0 }; // C++14 and C++17
Le point ici est que l'utilisation de guillemets simples dans l'un des fichiers d'en-tête purs en C ++ 11 peut entraîner des bogues surprenants dans les unités de traduction qui ciblent C ++ 14/17. Par conséquent, même si un fichier d'en-tête est écrit en C ++ 11, il doit être écrit avec soin pour s'assurer qu'il est compatible avec les versions ultérieures de la norme. La __cplusplus
directive peut être utile ici.
Les trois autres clauses de la norme comprennent:
C.3.2 Article 3: concepts de base
Changement : nouveau désallocateur habituel (sans placement)
Justification : Requis pour la désallocation de taille.
Effet sur la fonctionnalité d'origine : un code C ++ 2011 valide pourrait déclarer une fonction d'allocation de placement globale et une fonction de désallocation comme suit:
void operator new(std::size_t, std::size_t);
void operator delete(void*, std::size_t) noexcept;
Dans la présente Norme internationale, cependant, la déclaration de suppression d'opérateur peut correspondre à une suppression d'opérateur habituelle (sans placement) prédéfinie (3.7.4). Si c'est le cas, le programme est mal formé, comme c'était le cas pour les fonctions d'allocation des membres de classe et les fonctions de désallocation (5.3.4).
C.3.3 Article 7: déclarations
Modification : les fonctions membres non statiques constexpr ne sont pas implicitement des fonctions membres const.
Justification : nécessaire pour permettre aux fonctions membres de constexpr de muter l'objet.
Effet sur la caractéristique d'origine : Un code C ++ 2011 valide peut ne pas être compilé dans la présente Norme internationale.
Par exemple, le code suivant est valide en C ++ 2011 mais non valide dans la présente Norme internationale car il déclare la même fonction membre deux fois avec des types de retour différents:
struct S {
constexpr const int &f();
int &f();
};
C.3.4 Article 27: bibliothèque d'entrées / sorties
Changement : obtient n'est pas défini.
Justification : l'utilisation de get est considérée comme dangereuse.
Effet sur la fonctionnalité d'origine : un code C ++ 2011 valide qui utilise la fonction gets peut ne pas être compilé dans la présente Norme internationale.
Les incompatibilités potentielles entre C ++ 14 et C ++ 17 sont discutées en C.4. Étant donné que tous les fichiers d'en-tête non standard sont écrits en C ++ 11 (comme spécifié dans la question), ces problèmes ne se produiront pas, je ne les mentionnerai donc pas ici.
Je vais maintenant discuter de la compatibilité au niveau de l'éditeur de liens. En général, les raisons potentielles d'incompatibilités sont les suivantes:
Si le format du fichier objet résultant dépend du standard C ++ cible, l'éditeur de liens doit être en mesure de lier les différents fichiers objets. Dans GCC, LLVM et VC ++, ce n'est heureusement pas le cas. Autrement dit, le format des fichiers d'objets est le même quel que soit le standard cible, bien qu'il dépende fortement du compilateur lui-même. En fait, aucun des éditeurs de liens de GCC, LLVM et VC ++ n'a besoin de connaissances sur le standard C ++ cible. Cela signifie également que nous pouvons lier des fichiers objets déjà compilés (reliant statiquement le runtime).
Si la routine de démarrage du programme (la fonction qui appelle main
) est différente pour différentes normes C ++ et que les différentes routines ne sont pas compatibles entre elles, il ne serait pas possible de lier les fichiers objets. Dans GCC, LLVM et VC ++, ce n'est heureusement pas le cas. De plus, la signature de la main
fonction (et les restrictions qui s'y appliquent, voir Section 3.6 de la norme) est la même dans toutes les normes C ++, donc peu importe dans quelle unité de traduction elle existe.
En général, WPO peut ne pas fonctionner correctement avec des fichiers objets compilés à l'aide de différentes normes C ++. Cela dépend exactement des étapes du compilateur qui nécessitent une connaissance de la norme cible et des étapes non et de l'impact que cela a sur les optimisations inter-procédurales qui traversent les fichiers objets. Heureusement, GCC, LLVM et VC ++ sont bien conçus et n'ont pas ce problème (pas que je sache).
Par conséquent, GCC, LLVM et VC ++ ont été conçus pour permettre la compatibilité binaire entre les différentes versions de la norme C ++. Ce n'est cependant pas vraiment une exigence de la norme elle-même.
À propos, bien que le compilateur VC ++ propose le commutateur std , qui vous permet de cibler une version particulière de la norme C ++, il ne prend pas en charge le ciblage C ++ 11. La version minimale qui peut être spécifiée est C ++ 14, qui est la valeur par défaut à partir de Visual C ++ 2013 Update 3. Vous pouvez utiliser une version plus ancienne de VC ++ pour cibler C ++ 11, mais vous devrez alors utiliser différents compilateurs VC ++ pour compiler différentes unités de traduction qui ciblent différentes versions de la norme C ++, ce qui à tout le moins casserait WPO.
CAVEAT: Ma réponse n'est peut-être pas complète ou très précise.