Gesaan dan skop
Pustaka generik mesti membaca elemen kedudukan tetap daripada pek jenis atau pek hujah fungsi menggunakan pengindeksan pek C++26, sementara rantai alat yang lebih lama masih boleh membina. Terangkan pengindeksan pek ungkapan, pengindeksan pek jenis, kekangan indeks, pengesanan ciri, dan pelaksanaan keserasian.
Ini menguji peraturan bahasa dan sandaran kejuruteraan; jangan mendakwa bahawa setiap versi pengkompil telah pun melaksanakan ciri ini.
Perkara yang diuji oleh penemu duga
- Sama ada anda membezakan pengindeksan pek ungkapan daripada penentu pengindeksan pek untuk pek jenis.
- Sama ada anda tahu bahawa indeks mestilah pemalar masa kompilasi dan tidak boleh melebihi saiz pek.
- Sama ada anda menggunakan
__cpp_pack_indexinguntuk pengesanan keupayaan dan bukannya meneka daripada nama pengkompil. - Sama ada sandaran rekursif atau
tuplemengekalkan kontrak API.
Soalan penjelasan
- Adakah anda mengindeks pek nilai, pek jenis, atau pek parameter templat?
- Adakah indeks itu pemalar masa kompilasi atau integer masa jalanan?
- Pengkompil, mod bahasa, dan versi CI manakah yang disokong?
- Patutkah indeks di luar julat gagal dalam kekangan, atau diperiksa oleh pemanggil?
- Adakah sandaran mesti mengekalkan diagnostik dan kerumitan serta tingkah laku?
Jawapan 30 saat
"Pengindeksan pek C++26 memilih elemen pek ungkapan dengan indeks pemalar; pek jenis menggunakan penentu pengindeksan pek. Indeks mestilah pemalar masa kompilasi dan tidak boleh berada di luar julat. Integer masa jalanan masih memerlukan tatasusunan, tupel, atau jadual penghantaran (dispatch table). Saya akan mengesan __cpp_pack_indexing, menggunakan sintaks langsung apabila tersedia, menggunakan rekursi atau operasi tupel pada pengkompil lama, dan menguji batas serta tingkah laku API yang serupa."
Reka bentuk langkah demi langkah
1. Asingkan kedua-dua bentuk
Pengindeksan pek ungkapan memilih nilai daripada hujah fungsi; pengindeksan pek jenis memilih jenis daripada parameter templat. Kedua-duanya memindahkan pemilihan kedudukan ke dalam pemulaan templat dan mengurangkan rekursi yang ditulis secara manual, tetapi sintaks dan penggunaan seterusnya berbeza.
2. Memerlukan penilaian masa kompilasi
Indeks ialah ungkapan malar dalam konteks parameter templat bukan jenis. Integer masa jalanan tidak boleh menggantikannya. Jika pemilihan masa jalanan diperlukan, jelmakan pek sebagai tupel, tatasusunan, atau jadual fungsi dan lakukan penghantaran semasa masa jalanan.
template <std::size_t I, class... Ts>
using type_at = Ts...[I];
template <std::size_t I, class... Ts>
constexpr decltype(auto) value_at(Ts&&... values) {
return values...[I];
}3. Kendalikan pek kosong dan di luar julat
Pek kosong tidak mempunyai elemen yang boleh diindeks, dan indeks yang sama dengan atau melebihi saiz pek adalah tidak sah. Templat awam harus menolaknya lebih awal dengan kekangan requires yang memastikan indeks berada di bawah saiz pek. Ujian harus merangkumi panggilan kosong, pertama, terakhir, dan di luar julat.
4. Gunakan pengesanan ciri
cppreference merekodkan makro ujian ciri __cpp_pack_indexing dengan nilai 202311L. Semak makro bersama-sama dengan mod bahasa, dan gunakan CI pengkompil apabila diperlukan; rentetan versi pengkompil sahaja bukanlah kontrak keupayaan bahasa.
5. Reka bentuk sandaran rantai alat lama
Tanpa C++26, pek jenis boleh menggunakan templat rekursif atau utiliti pemilihan jenis tupel; pek nilai boleh membentuk tupel terlebih dahulu dan memanggil utiliti capaian kedudukan. Kekalkan kekangan batas yang sama dan kompil kedua-dua laluan dalam CI.
6. Nilaikan API dan diagnostik
Pengindeksan pek langsung memendekkan pelaksanaan, tetapi ia harus kekal di sebalik API yang stabil. Dokumentasikan mod standard yang diperlukan, pastikan diagnostik menamakan indeks dan saiz pek, dan buat penanda aras bagi masa kompilasi serta kod yang dijana untuk kedua-dua laluan dan bukannya membandingkan baris kod sumber semata-mata.
Model jawapan berkualiti tinggi
"Saya akan mengenal pasti entiti yang diindeks terlebih dahulu. Pengindeksan pek ungkapan C++26 memilih nilai, manakala pek jenis menggunakan penentu pengindeksan pek; indeks ialah pemalar masa kompilasi, jadi pek kosong dan di luar julat harus gagal pada sempadan kekangan. Kesan __cpp_pack_indexing; gunakan sintaks langsung pada rantai alat yang berkeupayaan dan gunakan rekursi, tuple_element, dan get pada rantai alat yang lebih lama di sebalik API yang sama. Indeks masa jalanan memerlukan tupel atau jadual penghantaran. Ujian meliputi kes kosong, sempadan, luar julat, kedua-dua mod bahasa, dan kedua-dua pelaksanaan."
Kesilapan lazim
- Menggunakan integer masa jalanan sebagai indeks templat → bahasa memerlukan pemalar → gunakan tupel, tatasusunan, atau jadual penghantaran.
- Hanya menyemak
__cplusplus→ sokongan ciri bergantung pada status pelaksanaan → semak__cpp_pack_indexingdan CI. - Membiarkan batas secara tersirat → ralat muncul jauh di dalam pemulaan templat → kekang antara muka lebih awal.
- Hanya melaksanakan pek jenis → panggilan pek nilai masih memerlukan rekursi → uji kedua-dua bentuk secara berasingan.
- Mengubah semantik dalam sandaran → rantai alat berkelakuan secara berbeza → kongsi kekangan, ujian, dan API yang stabil.
Soalan susulan dan jawapan
Bolehkah pengindeksan pek menyelesaikan pengindeksan masa jalanan?
Tidak. Ia memerlukan pemalar masa kompilasi. Pemilihan masa jalanan memerlukan tupel, tatasusunan, jadual fungsi, atau struktur penghantaran masa jalanan yang lain.
Mengapa menambah kekangan requires?
Bahasa akhirnya akan menolak indeks di luar julat, tetapi kekangan eksplisit memberikan diagnostik antara muka yang lebih awal dan lebih jelas serta membolehkan sandaran mendedahkan kontrak yang sama.
Adakah sandaran rekursif sentiasa lebih perlahan?
Tidak. Kod masa jalanan mungkin dioptimumkan kepada hasil yang sama, manakala kedalaman templat, masa kompilasi, dan diagnostik mungkin berbeza. Sahkan dengan matriks sokongan dan penanda aras dan bukannya menilai berdasarkan kepanjangan sintaks.