Ada dua bagian untuk menjawabnya. Kompatibilitas di tingkat compiler dan kompatibilitas di tingkat linker. Mari kita mulai dengan yang pertama.
anggap saja semua header ditulis dalam C ++ 11
Menggunakan kompilator yang sama berarti bahwa header perpustakaan standar dan file sumber yang sama (satu-satunya yang terkait dengan kompilator) akan digunakan terlepas dari standar C ++ target. Oleh karena itu, file header pustaka standar ditulis agar kompatibel dengan semua versi C ++ yang didukung oleh compiler.
Meskipun demikian, jika opsi compiler yang digunakan untuk mengompilasi unit terjemahan menetapkan standar C ++ tertentu, maka fitur apa pun yang hanya tersedia dalam standar yang lebih baru tidak boleh diakses. Ini dilakukan dengan menggunakan __cplusplus
direktif. Lihat file sumber vektor untuk contoh menarik tentang cara penggunaannya. Demikian pula, kompilator akan menolak fitur sintaksis apa pun yang ditawarkan oleh versi standar yang lebih baru.
Semua itu berarti asumsi Anda hanya dapat diterapkan ke file header yang Anda tulis. File header ini dapat menyebabkan ketidaksesuaian jika disertakan dalam unit terjemahan berbeda yang menargetkan standar C ++ berbeda. Ini dibahas dalam Lampiran C dari standar C ++. Ada 4 klausa, saya hanya akan membahas yang pertama, dan secara singkat menyebutkan sisanya.
C.3.1 Klausul 2: konvensi leksikal
Tanda kutip tunggal membatasi literal karakter dalam C ++ 11, sedangkan tanda kutip tunggal merupakan pemisah angka dalam C ++ 14 dan C ++ 17. Misalnya Anda memiliki definisi makro berikut di salah satu file header C ++ 11 murni:
#define M(x, ...) __VA_ARGS__
int x[2] = { M(1'2,3'4) };
Pertimbangkan dua unit terjemahan yang menyertakan file header, tetapi masing-masing menargetkan C ++ 11 dan C ++ 14. Saat menargetkan C ++ 11, koma di dalam tanda kutip tidak dianggap sebagai pemisah parameter; hanya ada satu parameter. Oleh karena itu, kodenya akan sama dengan:
int x[2] = { 0 };
Di sisi lain, saat menargetkan C ++ 14, tanda kutip tunggal diartikan sebagai pemisah digit. Oleh karena itu, kodenya akan sama dengan:
int x[2] = { 34, 0 };
Intinya di sini adalah bahwa menggunakan tanda kutip tunggal di salah satu file header C ++ 11 murni dapat menghasilkan bug yang mengejutkan dalam unit terjemahan yang menargetkan C ++ 14/17. Oleh karena itu, meskipun file header ditulis dalam C ++ 11, itu harus ditulis dengan hati-hati untuk memastikan bahwa itu kompatibel dengan versi standar yang lebih baru. The __cplusplus
direktif mungkin berguna di sini.
Tiga klausul lainnya dari standar tersebut meliputi:
C.3.2 Klausul 3: konsep dasar
Ganti : Deallocator biasa (non-penempatan) baru
Rasional : Diperlukan untuk deallocation ukuran.
Efek pada fitur asli : Kode C ++ 2011 yang valid dapat mendeklarasikan fungsi alokasi penempatan global dan fungsi deallokasi sebagai berikut:
void operator new(std::size_t, std::size_t);
void operator delete(void*, std::size_t) noexcept;
Dalam Standar Internasional ini, bagaimanapun, deklarasi penghapusan operator mungkin cocok dengan penghapusan operator biasa (non-penempatan) yang telah ditentukan sebelumnya (3.7.4). Jika demikian, programnya tidak bagus, seperti untuk fungsi alokasi anggota kelas dan fungsi deallokasi (5.3.4).
C.3.3 Klausul 7: deklarasi
Ubah : fungsi anggota non-statis constexpr tidak secara implisit fungsi anggota const.
Rasional : Diperlukan untuk mengizinkan fungsi anggota constexpr untuk memutasi objek.
Efek pada fitur asli : Kode C ++ 2011 yang valid mungkin gagal untuk dikompilasi dalam Standar Internasional ini.
Misalnya, kode berikut ini valid di C ++ 2011 tetapi tidak valid dalam Standar Internasional ini karena mendeklarasikan fungsi anggota yang sama dua kali dengan tipe pengembalian berbeda:
struct S {
constexpr const int &f();
int &f();
};
C.3.4 Ayat 27: perpustakaan input / output
Perubahan : mendapat tidak ditentukan.
Rasional : Penggunaan get dianggap berbahaya.
Efek pada fitur asli : Kode C ++ 2011 yang valid yang menggunakan fungsi gets mungkin gagal untuk dikompilasi dalam Standar Internasional ini.
Potensi ketidakcocokan antara C ++ 14 dan C ++ 17 dibahas di C.4. Karena semua file header non-standar ditulis dalam C ++ 11 (seperti yang ditentukan dalam pertanyaan), masalah ini tidak akan terjadi, jadi saya tidak akan menyebutkannya di sini.
Sekarang saya akan membahas kompatibilitas di tingkat linker. Secara umum, kemungkinan penyebab inkompatibilitas meliputi:
Jika format file objek yang dihasilkan bergantung pada standar C ++ target, penaut harus dapat menautkan file objek yang berbeda. Di GCC, LLVM, dan VC ++, untungnya tidak demikian. Artinya, format file objek adalah sama terlepas dari standar target, meskipun sangat bergantung pada kompiler itu sendiri. Nyatanya, tidak ada penaut GCC, LLVM, dan VC ++ yang membutuhkan pengetahuan tentang standar C ++ target. Ini juga berarti bahwa kita dapat menautkan file objek yang sudah dikompilasi (menghubungkan runtime secara statis).
Jika rutinitas startup program (fungsi yang memanggil main
) berbeda untuk standar C ++ yang berbeda dan rutinitas yang berbeda tidak kompatibel satu sama lain, maka tidak mungkin untuk menautkan file objek. Di GCC, LLVM, dan VC ++, untungnya tidak demikian. Selain itu, tanda tangan dari main
fungsi (dan batasan yang berlaku padanya, lihat Bagian 3.6 dari standar) adalah sama di semua standar C ++, jadi tidak masalah di unit terjemahan mana itu ada.
Secara umum, WPO mungkin tidak berfungsi dengan baik dengan file objek yang dikompilasi menggunakan standar C ++ yang berbeda. Hal ini bergantung pada tahapan mana dari compiler yang memerlukan pengetahuan tentang standar target dan tahapan mana yang tidak dan dampaknya pada pengoptimalan antar prosedural yang melintasi file objek. Untungnya, GCC, LLVM, dan VC ++ dirancang dengan baik dan tidak memiliki masalah ini (saya tidak menyadarinya).
Oleh karena itu, GCC, LLVM, dan VC ++ telah dirancang untuk mengaktifkan kompatibilitas biner di berbagai versi standar C ++. Ini sebenarnya bukan persyaratan standar itu sendiri.
Ngomong-ngomong, meskipun compiler VC ++ menawarkan std switch , yang memungkinkan Anda menargetkan versi tertentu dari standar C ++, compiler tersebut tidak mendukung penargetan C ++ 11. Versi minimum yang dapat ditentukan adalah C ++ 14, yang merupakan default mulai dari Visual C ++ 2013 Update 3. Anda dapat menggunakan versi lama VC ++ untuk menargetkan C ++ 11, tetapi kemudian Anda harus menggunakan kompiler VC ++ yang berbeda untuk mengkompilasi unit terjemahan berbeda yang menargetkan versi berbeda dari standar C ++, yang setidaknya akan merusak WPO.
PERHATIAN: Jawaban saya mungkin tidak lengkap atau sangat tepat.