Diberi fungsi yang sangat sepele,
int transform(int val) {
return (val + 7) / 8;
}
Seharusnya sangat jelas bahwa mudah untuk mengubah fungsi ini menjadi constexpr
fungsi, memungkinkan saya untuk menggunakannya ketika mendefinisikan constexpr
variabel, seperti:
constexpr int transform(int val) {
return (val + 7) / 8;
}
Asumsi saya adalah ini benar-benar perbaikan, karena fungsi masih dapat dipanggil dalam non- constexpr
konteks, dan sekarang dapat juga digunakan untuk membantu mendefinisikan variabel konstanta waktu kompilasi.
Pertanyaan saya adalah, adakah situasi di mana ini adalah ide yang buruk? Seperti, dengan membuat fungsi ini constexpr
, dapatkah saya menghadapi situasi di mana fungsi ini tidak lagi dapat digunakan dalam keadaan tertentu, atau di mana ia akan berperilaku buruk?
Jawaban:
Ini hanya penting jika fungsi ini merupakan bagian dari antarmuka publik, dan Anda ingin menjaga versi API-biner yang kompatibel di masa depan. Dalam hal ini, Anda harus memikirkan dengan cermat bagaimana Anda ingin mengembangkan API Anda, dan di mana Anda memerlukan titik ekstensi untuk perubahan di masa mendatang.
Itu membuat
constexpr
kualifikasi menjadi keputusan desain yang tidak dapat dibatalkan. Anda tidak dapat menghapus kualifikasi ini tanpa perubahan yang tidak kompatibel ke API Anda. Ini juga membatasi bagaimana Anda dapat mengimplementasikan fungsi itu, misalnya Anda tidak akan dapat melakukan logging dalam fungsi ini. Tidak setiap fungsi sepele akan tetap sepele dalam kekekalan.Itu berarti Anda sebaiknya menggunakan
constexpr
untuk fungsi yang secara inheren fungsi murni, dan itu akan benar-benar berguna pada waktu kompilasi (misalnya untuk pemrograman template). Tidaklah baik untuk membuat fungsi constexpr hanya karena implementasi saat ini kebetulan menjadi constexpr-mampu.Di mana evaluasi waktu kompilasi tidak diperlukan, menggunakan fungsi inline atau fungsi dengan tautan internal akan tampak lebih tepat
constexpr
. Semua varian ini memiliki kesamaan bahwa badan fungsi adalah "publik" dan tersedia di unit kompilasi yang sama dengan lokasi panggilan.Jika fungsi yang dipermasalahkan bukan bagian dari API publik yang stabil, ini bukan masalah karena Anda dapat mengubah desain sesuka hati. Tetapi karena Anda sekarang mengontrol semua situs panggilan, tidak perlu menandai fungsi constexpr "berjaga-jaga". Anda tahu apakah Anda menggunakan fungsi ini dalam konteks constexpr. Menambahkan kualifikasi yang tidak perlu maka mungkin dianggap membingungkan.
sumber
Menandai fungsi
constexpr
juga menjadikannya fungsi inline § [dcl.constexpr] / 1:inline
, pada gilirannya, berarti Anda perlu memasukkan definisi fungsi itu di setiap unit terjemahan yang dapat digunakan. Itu pada dasarnya berarticonstexpr
fungsi harus berupa:Sebagian besar fungsi khas yang ingin Anda deklarasikan di header dan tentukan dalam file sumber (dan apa pun yang menggunakannya hanya menyertakan header, lalu tautan ke file objek sumber itu)
constexpr
tidak akan berfungsi.Secara teori, saya kira Anda bisa memindahkan semuanya ke header dan hanya memiliki satu file sumber yang hanya mencakup semua header, tetapi ini akan merusak waktu kompilasi secara drastis, dan untuk sebagian besar proyek yang serius akan membutuhkan sejumlah besar memori untuk dikompilasi.
Suatu
constexpr
fungsi juga dibatasi dalam beberapa hal, jadi untuk beberapa fungsi mungkin tidak menjadi pilihan sama sekali. Pembatasan meliputi:constexpr
.try
blok.Saya telah melewatkan beberapa hal yang agak tidak jelas (mis., Itu juga tidak dapat memuat a
goto
asm
pernyataan atau ), tetapi Anda mendapatkan ide - untuk beberapa hal, itu tidak akan berhasil.Intinya: ya, ada beberapa situasi di mana ini akan menjadi ide yang buruk.
sumber