Saya bekerja pada aplikasi perangkat lunak besar yang harus dijalankan pada beberapa platform. Beberapa platform ini mendukung beberapa fitur C ++ 11 (mis. MSVS 2010) dan beberapa tidak mendukung apa pun (mis. GCC 4.3.x). Saya berharap situasi ini akan berlanjut selama beberapa tahun (tebakan terbaik saya: 3-5 tahun).
Mengingat itu, saya ingin mengatur antarmuka kompatibilitas sehingga (untuk tingkat apa pun yang mungkin) orang dapat menulis kode C ++ 11 yang masih akan dikompilasi dengan kompiler yang lebih tua dengan pemeliharaan minimum. Secara keseluruhan, tujuannya adalah untuk meminimalkan # ifdef sebanyak mungkin yang wajar sambil tetap mengaktifkan sintaks / fitur dasar C ++ 11 pada platform yang mendukungnya, dan memberikan emulasi pada platform yang tidak.
Mari kita mulai dengan std :: move (). Cara paling jelas untuk mencapai kompatibilitas adalah dengan meletakkan sesuatu seperti ini di file header umum:
#if !defined(HAS_STD_MOVE)
namespace std { // C++11 emulation
template <typename T> inline T& move(T& v) { return v; }
template <typename T> inline const T& move(const T& v) { return v; }
}
#endif // !defined(HAS_STD_MOVE)
Ini memungkinkan orang untuk menulis hal-hal seperti
std::vector<Thing> x = std::move(y);
... dengan impunitas. Ia melakukan apa yang mereka inginkan dalam C ++ 11 dan melakukan yang terbaik yang dapat dilakukan dalam C ++ 03. Ketika kami akhirnya menjatuhkan kompiler C ++ 03 yang terakhir, kode ini dapat tetap apa adanya.
Namun, menurut standar, adalah ilegal untuk menyuntikkan simbol baru ke std
namespace. Itulah teorinya. Pertanyaan saya adalah: secara praktis apakah ada salahnya melakukan ini sebagai cara untuk mencapai kompatibilitas ke depan?
Jawaban:
Saya telah bekerja untuk sementara dalam menjaga tingkat kompatibilitas ke depan dan ke belakang dalam program C ++ saya, sampai akhirnya saya harus membuat toolkit perpustakaan dari itu , yang
saya siapkan untuk rilissudah dirilis. Secara umum, selama Anda menerima bahwa Anda tidak akan mendapatkan kompatibilitas ke depan "sempurna" baik dalam fitur (beberapa hal tidak dapat ditiru) tidak dalam sintaks (Anda mungkin harus menggunakan makro, ruang nama alternatif untuk beberapa hal) maka Anda sudah siap.Ada banyak fitur bagus yang dapat ditiru di C ++ 03 pada level yang cukup untuk penggunaan praktis - dan tanpa semua kerumitan yang datang dengan mis .: Boost. Heck, bahkan proposal standar C ++ untuk
nullptr
menyarankan backport C ++ 03. Dan kemudian ada TR1 misalnya untuk semuanya C ++ 11-tetapi-kita-sudah-pratinjau-selama-tahun hal. Tidak hanya itu, beberapa fitur C ++ 14 seperti varian tegas, functors transparan danoptional
dapat diimplementasikan di C ++ 03!Hanya dua hal yang saya tahu yang tidak dapat sepenuhnya didukung adalah template constexpr dan variadic.
Berkenaan dengan seluruh masalah menambahkan barang ke namespace
std
, pandangan saya tentang hal itu adalah tidak masalah - sama sekali. Pikirkan Boost, salah satu pustaka C ++ yang paling penting dan relevan, dan implementasinya TR1: Boost.Tr1. Jika Anda ingin meningkatkan C ++, buat itu maju kompatibel dengan C ++ 11, maka menurut definisi Anda mengubahnya menjadi sesuatu yang bukan C ++ 03, jadi memblokir diri Anda sendiri atas Standar yang ingin Anda hindari atau tinggalkan. , sederhananya, kontraproduktif. Puritan akan mengeluh, tetapi menurut definisi orang tidak perlu peduli tentang mereka.Tentu saja, hanya karena Anda tidak akan mengikuti (03) Standar setelah semua tidak berarti Anda tidak dapat mencoba, atau akan dengan senang hati berkeliling melanggar itu. Itu bukan intinya. Selama Anda tetap sangat berhati-hati mengontrol apa yang ditambahkan ke
std
namespace, dan memiliki kontrol terhadap lingkungan tempat perangkat lunak Anda digunakan (mis .: lakukan pengujian!), Seharusnya tidak ada bahaya yang tidak dapat dilanggar sama sekali. Jika memungkinkan, tentukan semuanya dalam namespace yang terpisah dan hanya tambahkanusing
arahan ke namespacestd
sehingga Anda tidak menambahkan apa pun di luar apa yang "mutlak" perlu masukkan. Yang, IINM, kurang lebih seperti yang dilakukan Boost.TR1.Pembaruan (2013) : sebagai permintaan pertanyaan asli dan melihat beberapa komentar yang tidak dapat saya tambahkan karena kurangnya rep, berikut adalah daftar fitur C ++ 11 dan C ++ 14 dan tingkat portabilitasnya ke C ++ 03:
nullptr
: sepenuhnya dapat dilaksanakan mengingat dukungan resmi Komite; Anda mungkin harus memberikan beberapa spesialisasi type_traits juga sehingga dikenali sebagai tipe "asli".forward_list
: sepenuhnya dapat diterapkan, meskipun dukungan pengalokasi bergantung pada apa yang dapat diberikan oleh implementasi Tr1 Anda.vector<int> v = {1, 2, 3, 4};
: .:) : sepenuhnya dapat diterapkan, meskipun lebih banyak daripada yang diinginkan.static_assert
: hampir-sepenuhnya diimplementasikan ketika diimplementasikan sebagai makro (Anda hanya harus berhati-hati dengan koma).unique_ptr
: hampir-sepenuhnya dapat diterapkan, tetapi Anda juga akan memerlukan dukungan dari kode panggilan (untuk menyimpannya dalam wadah, dll); lihat di bawah ini sekalipun.static_cast<>
mungkin hampir mustahil.noexcept
: tergantung pada fitur kompiler Anda.auto
semantik dandecltype
: tergantung pada fitur compiler Anda - misalnya .:__typeof__
.int16_t
, dll): tergantung pada fitur kompiler Anda - atau Anda dapat mendelegasikan ke Portable stdint.h.::type
templat selamanyaconstexpr
: Tidak dapat diterapkan untuk pengetahuan saya.dynarray
: sepenuhnya dapat diterapkan.optional<>
: hampir sepenuhnya diimplementasikan asalkan kompiler C ++ 03 Anda mendukung pengaturan perataan.std::less<void>
untuk membuatnya berfungsi.assure
): sepenuhnya dapat diterapkan jika Anda ingin menegaskan, hampir sepenuhnya dapat diterapkan jika Anda ingin mengaktifkan lemparan sebagai gantinya.(Penafian: beberapa fitur ini diimplementasikan di pustaka C ++ backports saya yang saya tautkan di atas, jadi saya pikir saya tahu apa yang saya bicarakan ketika saya mengatakan "sepenuhnya" atau "hampir sepenuhnya".)
sumber
Ini pada dasarnya tidak mungkin. Pertimbangkan
std::unique_ptr<Thing>
. Jika mungkin untuk meniru referensi nilai sebagai perpustakaan, itu tidak akan menjadi fitur bahasa.sumber
std::unique_ptr
sana, tetapi beberapa fitur referensi rvalue lainnya tidak dapat diimplementasikan dalam C ++ 03, jadistd::forward
tidak mungkin. Hal lain adalah bahwastd::unique_ptr
itu tidak akan berguna, karena koleksi tidak akan menggunakan semantik langkah kecuali Anda mengganti semuanya.unique_ptr
. Lihatlah kegagalanauto_ptr
.unique_ptr
secara praktis adalah contoh buku teks dari kelas yang semantiknya secara fundamental diaktifkan oleh fitur bahasa.unique_ptr
secara fundamental diaktifkan oleh fitur bahasa. Ini tidak akan sangat berguna tanpa fitur itu. karena tanpa penerusan sempurna tidak akan dapat digunakan dalam banyak kasus dan penerusan sempurna memang memerlukan fitur itu.-std=c++0x
opsi untuk mengaktifkannya).std
namespace adalah "perilaku tidak terdefinisi". Itu artinya spesifikasinya tidak mengatakan apa yang akan terjadi. Tetapi jika Anda tahu bahwa pada platform tertentu perpustakaan standar tidak mendefinisikan sesuatu, langsung saja dan definisikan. Hanya berharap bahwa Anda harus memeriksa pada setiap platform apa yang Anda butuhkan dan apa yang dapat Anda tetapkan.unique_ptr
. Namun, itu tidak akan terlalu berguna, karena bergantung pada koleksi yang sebenarnya menggunakan semantik bergerak dan yang C ++ 03 jelas tidak akan.sumber