Die Antwort besteht aus zwei Teilen. Kompatibilität auf Compilerebene und Kompatibilität auf Linker-Ebene. Beginnen wir mit dem ersteren.
Nehmen wir an, alle Header wurden in C ++ 11 geschrieben
Die Verwendung desselben Compilers bedeutet, dass unabhängig vom C ++ - Zielstandard derselbe Standardbibliotheksheader und die gleichen Quelldateien (die dem Compiler zugeordneten Onces) verwendet werden. Daher werden die Header-Dateien der Standardbibliothek so geschrieben, dass sie mit allen vom Compiler unterstützten C ++ - Versionen kompatibel sind.
Wenn jedoch die zum Kompilieren einer Übersetzungseinheit verwendeten Compileroptionen einen bestimmten C ++ - Standard angeben, sollten auf alle Funktionen, die nur in neueren Standards verfügbar sind, nicht zugegriffen werden können. Dies geschieht mit der __cplusplus
Direktive. In der Vektorquelldatei finden Sie ein interessantes Beispiel für die Verwendung. Ebenso lehnt der Compiler alle syntaktischen Funktionen ab, die neuere Versionen des Standards bieten.
All dies bedeutet, dass Ihre Annahme nur für die von Ihnen geschriebenen Header-Dateien gelten kann. Diese Header-Dateien können Inkompatibilitäten verursachen, wenn sie in verschiedenen Übersetzungseinheiten enthalten sind, die auf unterschiedliche C ++ - Standards abzielen. Dies wird in Anhang C des C ++ - Standards erörtert. Es gibt 4 Klauseln, ich werde nur die erste diskutieren und den Rest kurz erwähnen.
C.3.1 Abschnitt 2: lexikalische Konventionen
Einfache Anführungszeichen begrenzen ein Zeichenliteral in C ++ 11, während sie in C ++ 14 und C ++ 17 Zifferntrennzeichen sind. Angenommen, Sie haben die folgende Makrodefinition in einer der reinen C ++ 11-Headerdateien:
#define M(x, ...) __VA_ARGS__
// Maybe defined as a field in a template or a type.
int x[2] = { M(1'2,3'4) };
Betrachten Sie zwei Übersetzungseinheiten, die die Header-Datei enthalten, jedoch auf C ++ 11 bzw. C ++ 14 abzielen. Bei der Ausrichtung auf C ++ 11 wird das Komma in Anführungszeichen nicht als Parametertrennzeichen betrachtet. Es gibt nur einen Parameter. Daher wäre der Code äquivalent zu:
int x[2] = { 0 }; // C++11
Wenn Sie dagegen auf C ++ 14 abzielen, werden die einfachen Anführungszeichen als Zifferntrennzeichen interpretiert. Daher wäre der Code äquivalent zu:
int x[2] = { 34, 0 }; // C++14 and C++17
Der Punkt hier ist, dass die Verwendung von einfachen Anführungszeichen in einer der reinen C ++ 11-Headerdateien zu überraschenden Fehlern in den Übersetzungseinheiten führen kann, die auf C ++ 14/17 abzielen. Selbst wenn eine Header-Datei in C ++ 11 geschrieben ist, muss sie daher sorgfältig geschrieben werden, um sicherzustellen, dass sie mit späteren Versionen des Standards kompatibel ist. Die __cplusplus
Richtlinie kann hier nützlich sein.
Die anderen drei Klauseln des Standards umfassen:
C.3.2 Abschnitt 3: Grundbegriffe
Änderung : Neuer üblicher (nicht platzierter) Deallocator
Begründung : Erforderlich für die Freigabe von Größen.
Auswirkung auf die ursprüngliche Funktion : Gültiger C ++ 2011-Code kann eine globale Platzierungszuweisungsfunktion und eine Freigabefunktion wie folgt deklarieren:
void operator new(std::size_t, std::size_t);
void operator delete(void*, std::size_t) noexcept;
In dieser internationalen Norm kann die Erklärung zum Löschen von Operatoren jedoch mit einem vordefinierten üblichen Löschen von Operatoren (ohne Platzierung) (3.7.4) übereinstimmen. In diesem Fall ist das Programm wie bei Zuordnungsfunktionen für Klassenmitglieder und Freigabefunktionen (5.3.4) fehlerhaft.
C.3.3 Abschnitt 7: Erklärungen
Änderung : Nicht statische Elementfunktionen von constexpr sind nicht implizit konstante Elementfunktionen.
Begründung : Erforderlich, damit constexpr-Mitgliedsfunktionen das Objekt mutieren können.
Auswirkung auf die ursprüngliche Funktion : Gültiger C ++ 2011-Code kann in diesem internationalen Standard möglicherweise nicht kompiliert werden.
Der folgende Code ist beispielsweise in C ++ 2011 gültig, in diesem internationalen Standard jedoch ungültig, da dieselbe Elementfunktion zweimal mit unterschiedlichen Rückgabetypen deklariert wird:
struct S {
constexpr const int &f();
int &f();
};
C.3.4 Abschnitt 27: Eingabe- / Ausgabebibliothek
Änderung : get ist nicht definiert.
Begründung : Die Verwendung von Gets wird als gefährlich angesehen.
Auswirkung auf die ursprüngliche Funktion : Gültiger C ++ 2011-Code, der die Funktion gets verwendet, kann in diesem internationalen Standard möglicherweise nicht kompiliert werden.
Mögliche Inkompatibilitäten zwischen C ++ 14 und C ++ 17 werden in C.4 erläutert. Da alle nicht standardmäßigen Header-Dateien in C ++ 11 geschrieben sind (wie in der Frage angegeben), treten diese Probleme nicht auf, sodass ich sie hier nicht erwähnen werde.
Jetzt werde ich die Kompatibilität auf Linker-Ebene diskutieren. Mögliche Gründe für Inkompatibilitäten sind im Allgemeinen:
- Das Format der Objektdateien.
- Programmstart- und -abschlussroutinen und der
main
Einstiegspunkt.
- Gesamtprogrammoptimierung (WPO).
Wenn das Format der resultierenden Objektdatei vom C ++ - Zielstandard abhängt, muss der Linker in der Lage sein, die verschiedenen Objektdateien zu verknüpfen. In GCC, LLVM und VC ++ ist dies glücklicherweise nicht der Fall. Das heißt, das Format der Objektdateien ist unabhängig vom Zielstandard dasselbe, obwohl es stark vom Compiler selbst abhängt. Tatsächlich erfordert keiner der Linker von GCC, LLVM und VC ++ Kenntnisse über den Ziel-C ++ - Standard. Dies bedeutet auch, dass wir bereits kompilierte Objektdateien verknüpfen können (statische Verknüpfung der Laufzeit).
Wenn die Programmstartroutine (die aufrufende Funktion main
) für verschiedene C ++ - Standards unterschiedlich ist und die verschiedenen Routinen nicht miteinander kompatibel sind, ist es nicht möglich, die Objektdateien zu verknüpfen. In GCC, LLVM und VC ++ ist dies glücklicherweise nicht der Fall. Darüber hinaus ist die Signatur der main
Funktion (und die für sie geltenden Einschränkungen, siehe Abschnitt 3.6 des Standards) in allen C ++ - Standards gleich, sodass es keine Rolle spielt, in welcher Übersetzungseinheit sie vorhanden ist.
Im Allgemeinen funktioniert WPO möglicherweise nicht gut mit Objektdateien, die mit unterschiedlichen C ++ - Standards kompiliert wurden. Dies hängt genau davon ab, welche Phasen des Compilers Kenntnisse des Zielstandards erfordern und welche nicht, und welche Auswirkungen dies auf prozedurale Optimierungen hat, die objektdateienübergreifend sind. Glücklicherweise sind GCC, LLVM und VC ++ gut gestaltet und haben dieses Problem nicht (das ist mir nicht bekannt).
Daher wurden GCC, LLVM und VC ++ entwickelt, um die Binärkompatibilität zwischen verschiedenen Versionen des C ++ - Standards zu ermöglichen. Dies ist jedoch nicht wirklich eine Anforderung des Standards selbst.
By the way, obwohl der VC ++ Compiler bietet die std Schalter , mit dem Sie eine bestimmte Version des C ++ Standard Ziel ermöglicht, unterstützt es nicht Targeting C ++ 11. Die Mindestversion, die angegeben werden kann, ist C ++ 14, die Standardeinstellung ab Visual C ++ 2013 Update 3. Sie könnten eine ältere Version von VC ++ verwenden, um auf C ++ 11 abzuzielen, müssten dann jedoch andere VC ++ - Compiler verwenden verschiedene Übersetzungseinheiten zu kompilieren, die auf verschiedene Versionen des C ++ - Standards abzielen, die zumindest WPO beschädigen würden.
CAVEAT: Meine Antwort ist möglicherweise nicht vollständig oder sehr präzise.