Saya mencoba menghitung panjang string literal pada waktu kompilasi. Untuk melakukannya, saya menggunakan kode berikut:
#include <cstdio>
int constexpr length(const char* str)
{
return *str ? 1 + length(str + 1) : 0;
}
int main()
{
printf("%d %d", length("abcd"), length("abcdefgh"));
}
Semuanya bekerja seperti yang diharapkan, program mencetak 4 dan 8. Kode assembly yang dihasilkan oleh clang menunjukkan bahwa hasil dihitung pada waktu kompilasi:
0x100000f5e: leaq 0x35(%rip), %rdi ; "%d %d"
0x100000f65: movl $0x4, %esi
0x100000f6a: movl $0x8, %edx
0x100000f6f: xorl %eax, %eax
0x100000f71: callq 0x100000f7a ; symbol stub for: printf
Pertanyaan saya: apakah dijamin oleh standar bahwa length
fungsi akan dievaluasi waktu kompilasi?
Jika ini benar, pintu untuk komputasi literal string waktu kompilasi baru saja dibuka untuk saya ... misalnya saya dapat menghitung hash pada waktu kompilasi dan banyak lagi ...
<cstdio>
dan kemudian panggilan::printf
tidak portabel. Standar hanya perlu<cstdio>
menyediakanstd::printf
.printf
dapat menyebabkan lebih sedikit kode untuk ditangani.Jawaban:
Ekspresi konstan tidak dijamin akan dievaluasi pada waktu kompilasi, kami hanya memiliki kutipan non-normatif dari draf bagian standar C ++
5.19
Ekspresi konstan yang mengatakan ini:Anda dapat menetapkan hasilnya ke
constexpr
variabel untuk memastikannya dievaluasi pada waktu kompilasi, kita dapat melihat ini dari referensi C ++ 11 Bjarne Stroustrup yang mengatakan ( penekanan saya ):Sebagai contoh:
constexpr int len1 = length("abcd") ;
Bjarne Stroustrup memberikan ringkasan kapan kami dapat memastikan evaluasi waktu kompilasi dalam entri blog isocpp ini dan mengatakan:
Jadi ini menguraikan dua kasus yang harus dievaluasi pada waktu kompilasi:
shall be ... converted constant expression
ataushall be ... constant expression
digunakan, seperti terikat larik.constexpr
seperti yang saya uraikan di atas.sumber
constexpr int x = 5;
, perhatikan bahwa itu tidak memerlukan nilai pada waktu kompilasi (dengan asumsi itu tidak digunakan sebagai parameter templat atau yang lainnya) dan benar-benar memancarkan kode yang menghitung nilai awal saat runtime menggunakan 5 nilai langsung dari 1 dan 4 operasi tambahan. Contoh yang lebih realistis: kompilator mungkin mencapai batas rekursi dan menunda komputasi hingga waktu proses. Kecuali jika Anda melakukan sesuatu yang memaksa kompilator untuk benar-benar menggunakan nilai, "dijamin akan dievaluasi pada waktu kompilasi" adalah masalah QOI.constexpr
perhitungan Anda dari kejahatan belaka. Bahkan Anda bebas menunggu 1 detik per karakter di baris sumber tertentu, atau mengambil baris sumber tertentu dan menggunakannya untuk menyemai posisi catur, lalu memainkan kedua sisi untuk menentukan siapa yang menang.Sangat mudah untuk mengetahui apakah panggilan ke suatu
constexpr
fungsi menghasilkan ekspresi konstanta inti atau hanya dioptimalkan:Gunakan dalam konteks di mana ekspresi konstan diperlukan.
int main() { constexpr int test_const = length("abcd"); std::array<char,length("abcdefgh")> test_const2; }
sumber
-pedantic
, jika Anda menggunakan gcc. Jika tidak, Anda tidak akan mendapatkan peringatan dan kesalahanenum { Whatever = length("str") }
?static_assert(length("str") == 3, "");
constexpr auto test = /*...*/;
mungkin yang paling umum dan mudah.Sebagai catatan, kompiler modern (seperti gcc-4.x) melakukannya
strlen
untuk literal string pada waktu kompilasi karena biasanya didefinisikan sebagai fungsi intrinsik . Tanpa pengoptimalan yang diaktifkan. Meskipun hasilnya bukan konstanta waktu kompilasi.Misalnya:
printf("%zu\n", strlen("abc"));
Hasil dalam:
movl $3, %esi # strlen("abc") movl $.LC0, %edi # "%zu\n" movl $0, %eax call printf
sumber
strlen
merupakan fungsi-fno-builtins
strlen
adalahconstexpr
untuk saya, bahkan dengan-fno-nonansi-builtins
(sepertinya-fno-builtins
tidak ada lagi di g ++). Saya mengatakan "constexpr", karena saya bisa melakukan initemplate<int> void foo();
danfoo<strlen("hi")>();
g ++ - 4.8.4Izinkan saya mengusulkan fungsi lain yang menghitung panjang string pada waktu kompilasi tanpa rekursif.
template< size_t N > constexpr size_t length( char const (&)[N] ) { return N-1; }
Lihat kode contoh ini di ideone .
sumber
char temp[256]; sprintf(temp, "%u", 2); if(1 != length(temp)) printf("Your solution doesn't work");
ideone.com/IfKUHVTidak ada jaminan bahwa suatu
constexpr
fungsi dievaluasi pada waktu kompilasi, meskipun kompilator yang wajar akan melakukannya pada tingkat pengoptimalan yang sesuai diaktifkan. Di sisi lain, parameter template harus dievaluasi pada waktu kompilasi.Saya menggunakan trik berikut untuk memaksa evaluasi pada waktu kompilasi. Sayangnya ini hanya bekerja dengan nilai integral (yaitu tidak dengan nilai floating point).
template<typename T, T V> struct static_eval { static constexpr T value = V; };
Sekarang, jika Anda menulis
if (static_eval<int, length("hello, world")>::value > 7) { ... }
Anda dapat yakin bahwa
if
pernyataan tersebut adalah konstanta waktu kompilasi tanpa overhead waktu proses.sumber
len
beingconstexpr
meanslength
harus dievaluasi pada waktu kompilasi.if
-kondisi (di mana itu penting kompiler melakukan penghapusan kode mati) yang awalnya saya gunakan triknya.Penjelasan singkat dari entri Wikipedia tentang ekspresi konstanta yang digeneralisasi :
Memiliki
constexpr
kata kunci sebelum definisi fungsi menginstruksikan kompilator untuk memeriksa apakah batasan ini terpenuhi. Jika ya, dan fungsinya dipanggil dengan konstanta, nilai yang dikembalikan dijamin konstan dan dengan demikian dapat digunakan di mana pun ekspresi konstan diperlukan.sumber