Tampak bagi saya bahwa memiliki "fungsi yang selalu mengembalikan 5" adalah memecah atau melemahkan arti "memanggil fungsi". Pasti ada alasan, atau kebutuhan untuk kemampuan ini atau itu tidak akan ada di C ++ 11. Kenapa disana?
// preprocessor.
#define MEANING_OF_LIFE 42
// constants:
const int MeaningOfLife = 42;
// constexpr-function:
constexpr int MeaningOfLife () { return 42; }
Tampaknya bagi saya bahwa jika saya menulis sebuah fungsi yang mengembalikan nilai literal, dan saya datang ke tinjauan kode, seseorang akan memberi tahu saya, maka saya harusnya, menyatakan nilai konstan daripada menulis return 5.
constexpr
? Jika demikian, saya dapat melihat penggunaannya.const
. Bahkan, niat diamanatkan adalah berguna ! Dimensi array adalah contoh kanonik.Jawaban:
Misalkan itu melakukan sesuatu yang sedikit lebih rumit.
Sekarang Anda memiliki sesuatu yang dapat dievaluasi ke konstan sambil mempertahankan keterbacaan yang baik dan memungkinkan pemrosesan yang sedikit lebih kompleks daripada hanya menetapkan konstanta ke angka.
Ini pada dasarnya memberikan bantuan yang baik untuk pemeliharaan karena menjadi lebih jelas apa yang Anda lakukan. Ambil
max( a, b )
contoh:Itu pilihan yang cukup sederhana di sana tetapi itu berarti bahwa jika Anda menelepon
max
dengan nilai konstan itu secara eksplisit dihitung pada waktu kompilasi dan bukan pada saat runtime.Contoh bagus lainnya adalah
DegreesToRadians
fungsi. Semua orang menemukan derajat lebih mudah dibaca daripada radian. Meskipun Anda mungkin tahu bahwa 180 derajat dalam radian, itu jauh lebih jelas ditulis sebagai berikut:Banyak info bagus di sini:
http://en.cppreference.com/w/cpp/language/constexpr
sumber
pengantar
constexpr
tidak diperkenalkan sebagai cara untuk memberitahu implementasi bahwa sesuatu dapat dievaluasi dalam konteks yang membutuhkan ekspresi konstan ; implementasi yang sesuai telah dapat membuktikan ini sebelum C ++ 11.Sesuatu yang tidak bisa dibuktikan oleh implementasi adalah maksud dari kode tertentu:
Apa jadinya dunia tanpa ini
constexpr
?Katakanlah Anda sedang mengembangkan perpustakaan dan menyadari bahwa Anda ingin dapat menghitung jumlah setiap bilangan bulat dalam interval
(0,N]
.Kurangnya niat
Kompiler dapat dengan mudah membuktikan bahwa fungsi di atas dapat dipanggil dalam ekspresi konstan jika argumen yang disampaikan diketahui selama terjemahan; tetapi Anda belum menyatakan ini sebagai maksud - itu terjadi begitu saja.
Sekarang orang lain datang, membaca fungsi Anda, melakukan analisis yang sama dengan kompiler; " Oh, fungsi ini dapat digunakan dalam ekspresi konstan!" , dan menulis potongan kode berikut.
Optimalisasi
Anda, sebagai pengembang perpustakaan "luar biasa" , memutuskan bahwa
f
akan menyimpan hasil cache ketika dipanggil; siapa yang ingin menghitung set nilai yang sama berulang kali?Hasil
Dengan memperkenalkan optimasi konyol Anda, Anda baru saja melanggar setiap penggunaan fungsi Anda yang kebetulan berada dalam konteks di mana ekspresi konstan diperlukan.
Anda tidak pernah berjanji bahwa fungsi tersebut dapat digunakan dalam ekspresi konstan , dan tanpa itu
constexpr
tidak akan ada cara untuk memberikan janji seperti itu.Jadi, mengapa kita perlu
constexpr
?Penggunaan utama constexpr adalah untuk menyatakan niat .
Jika suatu entitas tidak ditandai sebagai
constexpr
- itu tidak pernah dimaksudkan untuk digunakan dalam ekspresi konstan ; dan bahkan jika itu benar, kami bergantung pada kompiler untuk mendiagnosis konteks tersebut (karena itu mengabaikan maksud kami).sumber
constexpr
ekspresi. Dengan kata lain, hampir semua hal dapat dianotasiconstexpr
(mungkin suatu hari akan hilang begitu saja karena ini?), Dan kecuali seseorang memiliki kriteria kapan akan digunakanconstexpr
atau tidak, hampir semua kode akan ditulis seperti itu .I/O
,syscall
dandynamic memory allocation
pasti cann't ditandai sebagaiconstexpr
Selain itu, tidak semuanya harus menjadiconstexpr
.constexpr
jaminan adalah semacam perilaku. Sama seperticonst
halnya.int f (int n) { return n > 0 ? n + f (n-1) : n;} T arr[f(10)];
saya tidak bisa mengkompilasi ini di mana saja?Ambil
std::numeric_limits<T>::max()
: untuk alasan apa pun, ini adalah metode.constexpr
akan bermanfaat di sini.Contoh lain: Anda ingin mendeklarasikan C-array (atau a
std::array
) yang sebesar array lain. Cara untuk melakukan ini saat ini adalah seperti ini:Tapi bukankah lebih baik menulis:
Terima kasih
constexpr
, Anda dapat:sumber
constexpr
memaksa komplier untuk membuat fungsi mengembalikan nilai waktu kompilasi (jika bisa).constexpr
itu tidak dapat digunakan dalam deklarasi ukuran array, atau sebagai argumen template, terlepas dari apakah hasil dari panggilan fungsi adalah konstanta waktu kompilasi atau tidak. Keduanya pada dasarnya adalah satu-satunya use-case untukconstexpr
tetapi setidaknya argumen templat use-case agak penting.-pedantic
opsi dan itu akan ditandai sebagai kesalahan.constexpr
fungsinya sangat bagus dan tambahan yang bagus untuk c ++. Namun, Anda benar karena sebagian besar masalah yang dipecahkan dapat diatasi dengan makro secara tidak hati-hati.Namun, salah satu penggunaan
constexpr
tidak memiliki konstanta yang diketikkan C ++ 03, diketik.sumber
four
tidak menyelesaikan. Saya harus benar-benar menggali untuk mencari siapa yang mengambil alamatstatic const
variabel saya .four
ataufive
berada di lingkup.enum class
tipe baru , itu memperbaiki beberapa masalah enum.Dari apa yang saya baca, kebutuhan akan constexpr berasal dari masalah dalam metaprogramming. Kelas trait mungkin memiliki konstanta yang direpresentasikan sebagai fungsi, pikirkan: numeric_limits :: max (). Dengan constexpr, tipe-tipe fungsi tersebut dapat digunakan dalam metaprogramming, atau sebagai array array, dll.
Contoh lain dari bagian atas kepala saya adalah bahwa untuk antarmuka kelas, Anda mungkin ingin tipe turunan mendefinisikan konstanta mereka sendiri untuk beberapa operasi.
Edit:
Setelah mencari-cari di SO, sepertinya orang lain telah datang dengan beberapa contoh dari apa yang mungkin dilakukan dengan constexprs.
sumber
constexpr
lebih khusus berguna dalam kompiler dengan sistem evaluasi ekspresi kompilasi-waktu yang kuat. C ++ benar-benar tidak memiliki rekan di domain itu. (itu pujian yang kuat untuk C ++ 11, IMHO)Dari pidato Stroustrup di "Going Native 2012":
sumber
Penggunaan lain (belum disebutkan) adalah
constexpr
konstruktor. Ini memungkinkan pembuatan konstanta waktu kompilasi yang tidak harus diinisialisasi selama runtime.Pasangkan dengan literal yang ditentukan pengguna dan Anda memiliki dukungan penuh untuk kelas yang ditentukan pengguna literal.
sumber
Dulu ada pola dengan metaprogramming:
Saya percaya
constexpr
diperkenalkan untuk membiarkan Anda menulis konstruksi seperti itu tanpa perlu template dan konstruksi aneh dengan spesialisasi, SFINAE, dan sebagainya - tetapi persis seperti Anda akan menulis fungsi run-time, tetapi dengan jaminan bahwa hasilnya akan ditentukan dalam kompilasi -waktu.Namun, perhatikan bahwa:
Kompilasi dengan ini
g++ -O3
dan Anda akan melihat bahwafact(10)
memang dievakuasi pada waktu kompilasi!Kompiler yang sadar VLA (jadi kompiler C dalam mode C99 atau kompiler C ++ dengan ekstensi C99) bahkan memungkinkan Anda untuk melakukan:
Tapi itu bukan C + + standar saat ini -
constexpr
sepertinya cara untuk memerangi ini (bahkan tanpa VLA, dalam kasus di atas). Dan masih ada masalah perlunya memiliki ekspresi konstan "formal" sebagai argumen templat.sumber
std::array<int, fact(2)>
dan Anda akan melihat fakta () tidak dievaluasi pada waktu kompilasi. Hanya saja pengoptimal GCC melakukan pekerjaan dengan baik.Baru saja mulai beralih proyek ke c ++ 11 dan menemukan situasi yang sangat baik untuk constexpr yang membersihkan metode alternatif melakukan operasi yang sama. Titik kunci di sini adalah bahwa Anda hanya dapat menempatkan fungsi ke dalam deklarasi ukuran array ketika dinyatakan constexpr. Ada beberapa situasi di mana saya bisa melihat ini menjadi sangat berguna bergerak maju dengan bidang kode yang saya ikuti.
sumber
static inline constexpr const auto
mungkin lebih baik.Semua jawaban lainnya bagus, saya hanya ingin memberikan contoh keren dari satu hal yang dapat Anda lakukan dengan constexpr yang luar biasa. See-Phit ( https://github.com/rep-movsd/see-phit/blob/master/seephit.h ) adalah waktu kompilasi parser HTML dan mesin templat. Ini berarti Anda dapat memasukkan HTML dan keluar pohon yang dapat dimanipulasi. Setelah penguraian dilakukan pada waktu kompilasi dapat memberi Anda sedikit kinerja ekstra.
Dari contoh halaman github:
sumber
Contoh dasar Anda menyajikan argumen yang sama dengan konstanta itu sendiri. Mengapa menggunakan
lebih
Karena cara itu lebih bisa dipertahankan. Menggunakan constexpr jauh lebih cepat untuk menulis dan membaca daripada teknik pemrograman yang ada.
sumber
Itu dapat mengaktifkan beberapa optimisasi baru.
const
secara tradisional adalah petunjuk untuk sistem tipe, dan tidak dapat digunakan untuk optimasi (misalnyaconst
fungsi anggota dapatconst_cast
dan memodifikasi objek, secara hukum, jadiconst
tidak dapat dipercaya untuk optimasi).constexpr
berarti ekspresi benar - benar konstan, asalkan input ke fungsi adalah const. Mempertimbangkan:Jika ini diekspos di beberapa modul lain, kompiler tidak dapat mempercayai yang
GetNumber()
tidak akan mengembalikan nilai yang berbeda setiap kali dipanggil - bahkan secara berurutan tanpa ada panggilan non-const di antaranya - karenaconst
bisa saja dibuang dalam implementasi. (Jelas setiap programmer yang melakukan ini harus ditembak, tetapi bahasa mengizinkannya, oleh karena itu kompiler harus mematuhi aturan.)Menambahkan
constexpr
:Kompiler sekarang dapat menerapkan optimasi di mana nilai kembali
GetNumber()
cache dan menghilangkan panggilan tambahanGetNumber()
, karenaconstexpr
merupakan jaminan kuat bahwa nilai kembali tidak akan berubah.sumber
const
dapat digunakan dalam optimasi ... Ini adalah perilaku yang tidak terdefinisi untuk mengubah nilai yang didefinisikan const bahkan setelahconst_cast
IIRC. Saya berharap ini konsisten untukconst
fungsi anggota, tetapi saya harus memeriksanya dengan standar. Ini berarti bahwa kompiler dapat dengan aman melakukan optimasi di sana.int x
vsconst int x
), maka aman untuk memodifikasinya denganconst_cast
-menyingkirkan const pada pointer / referensi untuk itu. Jika tidak,const_cast
akan selalu memunculkan perilaku yang tidak terdefinisi, dan menjadi sia-sia :) Dalam kasus ini, kompiler tidak memiliki informasi tentang kesesuaian objek asli, jadi ia tidak dapat mengatakannya.int GetNumber() const = 0;
) harus mendeklarasikanGetNumber()
metode virtual. Kedua (constexpr int GetNumber() const = 0;
) tidak valid karena specifier murni (= 0
) menyiratkan metode menjadi virtual, tetapi constexpr tidak boleh virtual (ref: en.cppreference.com/w/cpp/language/constexpr )Kapan harus menggunakan
constexpr
:sumber
constexpr
lebih disukai daripada makro preprocessor atauconst
.Ini berguna untuk sesuatu seperti
Ikat ini dengan kelas sifat atau sejenisnya dan itu menjadi sangat berguna.
sumber