Salah satu sudut konsep C ++ 20 adalah bahwa ada situasi tertentu di mana Anda harus menulis requires requires
. Misalnya, contoh ini dari [expr.prim.req] / 3 :
Sebuah membutuhkan ekspresi juga dapat digunakan dalam membutuhkan-klausul ([suhu]) sebagai cara menulis iklan kendala hoc pada argumen template yang seperti di bawah ini:
template<typename T> requires requires (T x) { x + x; } T add(T a, T b) { return a + b; }
Yang pertama membutuhkan memperkenalkan yang membutuhkan-klausa , dan yang kedua memperkenalkan yang membutuhkan-ekspresi .
Apa alasan teknis di balik memerlukan requires
kata kunci kedua itu ? Mengapa kita tidak bisa membiarkan tulisan saja:
template<typename T>
requires (T x) { x + x; }
T add(T a, T b) { return a + b; }
(Catatan: tolong jangan jawab bahwa tata bahasanya requires
)
c++
c++-concepts
c++20
Barry
sumber
sumber
noexcept(noexcept(...))
.requires
homonim menurut saya: mereka terlihat sama, mengeja sama, mencium aroma yang sama, tetapi secara intrinsik berbeda. Jika saya menyarankan perbaikan, saya akan menyarankan untuk mengganti nama salah satunya.co_requires
? (Maaf, tidak bisa menahan).long long
.Jawaban:
Itu karena tata bahasa mengharuskannya. Itu benar.
Sebuah
requires
kendala tidak harus menggunakanrequires
ekspresi. Ia dapat menggunakan ekspresi konstanta boolean yang lebih atau kurang sembarang. Karena itu,requires (foo)
harus menjadirequires
kendala yang sah .Sebuah
requires
ekspresi (hal yang bahwa tes apakah hal-hal tertentu mengikuti kendala tertentu) adalah konstruk yang berbeda; itu hanya diperkenalkan oleh kata kunci yang sama.requires (foo f)
akan menjadi awal darirequires
ekspresi yang valid .Apa yang Anda inginkan adalah bahwa jika Anda menggunakan
requires
di tempat yang menerima kendala, Anda harus dapat membuat "batasan + ekspresi" keluar darirequires
klausa.Jadi, inilah pertanyaannya: jika Anda menempatkan
requires (foo)
ke suatu tempat yang sesuai untuk kendala memerlukan ... seberapa jauh parser harus pergi sebelum dapat menyadari bahwa ini adalah kendala membutuhkan daripada ekspresi + kendala seperti yang Anda inginkan menjadi?Pertimbangkan ini:
Jika
foo
adalah tipe, maka(foo)
adalah daftar parameter dari ekspresi yang diperlukan, dan semua yang ada di{}
dalamnya bukan tubuh fungsi tetapi tubuhrequires
ekspresi itu. Kalau tidak,foo
adalah ekspresi dalamrequires
klausa.Nah, Anda bisa mengatakan bahwa kompiler harus mencari tahu apa
foo
yang pertama. Tetapi C ++ benar - benar tidak menyukainya ketika tindakan dasar untuk mengurai urutan token mensyaratkan bahwa kompiler mengetahui apa yang dimaksud oleh pengidentifikasi sebelum dapat memahami token tersebut. Ya, C ++ peka konteks, jadi ini memang terjadi. Tetapi komite lebih suka menghindarinya jika memungkinkan.Jadi ya, itu tata bahasa.
sumber
requires
muncul setelah<>
serangkaian argumen templat atau setelah daftar parameter fungsi, maka itu memerlukan-klausa. Jikarequires
muncul di mana ekspresi itu valid, maka itu adalah ekspresi yang diharuskan. Ini dapat ditentukan oleh struktur pohon parse, bukan isi dari pohon parse (spesifik tentang bagaimana pengidentifikasi didefinisikan akan menjadi isi pohon).concept
danrequires
. Memperkenalkan yang ketiga, ketika yang kedua akan dapat mencakup kedua kasus tanpa masalah tata bahasa dan beberapa masalah yang dihadapi pengguna, hanya sia-sia. Bagaimanapun, satu-satunya masalah visual adalah bahwa kata kunci tersebut terjadi berulang dua kali.Situasinya persis analog dengan
noexcept(noexcept(...))
. Tentu, ini terdengar lebih seperti hal yang buruk daripada hal yang baik, tetapi izinkan saya menjelaskannya. :) Kami akan mulai dengan apa yang sudah Anda ketahui:C ++ 11 memiliki "
noexcept
-clauses" dan "noexcept
-expressions." Mereka melakukan hal yang berbeda.A-
noexcept
klausa mengatakan, "Fungsi ini seharusnya tidak kecuali ketika ... (suatu kondisi)." Ini berjalan pada deklarasi fungsi, mengambil parameter boolean, dan menyebabkan perubahan perilaku pada fungsi yang dideklarasikan.noexcept
Ekspresi A mengatakan, "Kompiler, tolong katakan padaku apakah (beberapa ekspresi) ada kecuali." Itu sendiri merupakan ekspresi boolean. Ia tidak memiliki "efek samping" pada perilaku program - hanya meminta kompiler untuk menjawab pertanyaan ya / tidak. "Apakah ungkapan ini bukan pengecualian?"Kami bisa sarang
noexcept
-expression di dalamnoexcept
-clause, tapi kami biasanya menganggap gaya buruk untuk melakukannya.Ini dianggap gaya yang lebih baik untuk merangkum
noexcept
ekspresi-dalam tipe-sifat.C ++ 2a Working Draft memiliki "
requires
-clauses" dan "requires
-expressions." Mereka melakukan hal yang berbeda.A-
requires
klausa mengatakan, "Fungsi ini harus berpartisipasi dalam resolusi kelebihan ketika ... (suatu kondisi)." Ini berjalan pada deklarasi fungsi, mengambil parameter boolean, dan menyebabkan perubahan perilaku pada fungsi yang dideklarasikan.requires
Ekspresi A mengatakan, "Kompiler, tolong katakan padaku apakah (beberapa ekspresi) terbentuk dengan baik." Itu sendiri merupakan ekspresi boolean. Ia tidak memiliki "efek samping" pada perilaku program - hanya meminta kompiler untuk menjawab pertanyaan ya / tidak. "Apakah ungkapan ini terbentuk dengan baik?"Kami bisa sarang
requires
-expression di dalamrequires
-clause, tapi kami biasanya menganggap gaya buruk untuk melakukannya.Ini dianggap gaya yang lebih baik untuk merangkum
requires
ekspresi-dalam tipe-karakter ...... atau dalam konsep (C ++ 2a Working Draft).
sumber
noexcept
memiliki masalah yangnoexcept(f())
bisa berarti baik menafsirkanf()
sebagai boolean yang kami gunakan untuk mengatur spesifikasi atau memeriksa apakah atau tidakf()
adalahnoexcept
.requires
tidak memiliki ambiguitas ini karena ekspresi yang memeriksa validitasnya harus sudah diperkenalkan dengan{}
s. Setelah itu, argumen pada dasarnya adalah "tata bahasa mengatakan demikian."{}
bersifat opsional.{}
bukan opsional, bukan itu yang ditampilkan komentar. Namun, itu adalah komentar yang bagus yang menunjukkan ambiguitas penguraian. Mungkin akan menerima komentar itu (dengan beberapa penjelasan) sebagai jawaban mandirirequires is_nothrow_incrable_v<T>;
seharusnyarequires is_incrable_v<T>;
Saya pikir halaman konsep cppreference menjelaskan hal ini. Saya bisa menjelaskan dengan "matematika" sehingga bisa dikatakan, mengapa ini harus seperti ini:
Jika Anda ingin mendefinisikan konsep, Anda melakukan ini:
Jika Anda ingin mendeklarasikan fungsi yang menggunakan konsep itu, Anda melakukan ini:
Sekarang jika Anda tidak ingin mendefinisikan konsep secara terpisah, saya kira yang harus Anda lakukan adalah beberapa substitusi. Ambil bagian ini
requires (T x) { x + x; };
dan gantiAddable<T>
bagian itu, dan Anda akan mendapatkan:itulah yang Anda tanyakan.
sumber
template<typename T> requires (T x) { x + x; }
dan mensyaratkan bahwa persyaratan dapat berupa klausa dan ungkapan?requires
klausul -as-kendala tidak harus menjadirequires
-expression. Itu hanya satu kemungkinan penggunaannya.requires requires
. Mereka bisa menambahkan sesuatu ke tata bahasa untuk memungkinkantemplate<typename T> requires (T x) { x + x; }
tetapi mereka tidak. Barry ingin tahu mengapa mereka tidaktemplate<class T> void f(T) requires requires(T (x)) { (void)x; };
berarti sesuatu yang berbeda jika Anda menghapus salah satu darirequires
es.Saya menemukan komentar dari Andrew Sutton (salah satu penulis Konsep, yang mengimplementasikannya dalam gcc) sangat membantu dalam hal ini, jadi saya pikir saya akan mengutipnya di sini secara keseluruhan:
sumber
Karena Anda mengatakan bahwa benda A memiliki persyaratan B, dan persyaratan B memiliki persyaratan C.
Hal A membutuhkan B yang pada gilirannya membutuhkan C.
Klausa "membutuhkan" itu sendiri membutuhkan sesuatu.
Anda memiliki benda A (membutuhkan B (membutuhkan C)).
Ah. :)
sumber
requires
secara konseptual bukanlah hal yang sama (satu adalah klausa, satu ungkapan). Bahkan, jika saya mengerti dengan benar, dua set()
dalamrequires (requires (T x) { x + x; })
memiliki makna yang sangat berbeda (bagian luar adalah opsional dan selalu berisi boolean constexpr; bagian dalam menjadi bagian wajib dari memperkenalkan ekspresi yang membutuhkan dan tidak memungkinkan ekspresi yang sebenarnya).