Untuk mendefinisikan konstanta waktu kompilasi dari tipe integral seperti berikut (pada fungsi dan ruang lingkup kelas), sintaks mana yang terbaik?

static const int kMagic = 64; // (1)
constexpr int kMagic = 64;    // (2)

(1) berfungsi juga untuk kompiler C++98/03, sebaliknya (2) membutuhkan setidaknya C++11. Apakah ada perbedaan lain di antara keduanya? Haruskah satu atau yang lain lebih disukai dalam kode C++ modern, dan mengapa?


EDIT

Saya mencoba kode contoh ini dengan CE Godbolt:

int main()
{
#define USE_STATIC_CONST
#ifdef USE_STATIC_CONST
  static const int kOk = 0;
  static const int kError = 1;
#else
  constexpr int kOk = 0;
  constexpr int kError = 1;
#endif
  return kOk;
}

Dan untuk kasus static const ini adalah perakitan yang dihasilkan oleh GCC 6.2:

main::kOk:
        .zero   4
main::kError:
        .long   1
main:
        push    rbp
        mov     rbp, rsp
        mov     eax, 0
        pop     rbp
        ret

Di sisi lain, untuk constexpr adalah:

main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 0
        mov     DWORD PTR [rbp-8], 1
        mov     eax, 0
        pop     rbp
        ret

Meskipun pada -O3 dalam kedua kasus saya mendapatkan Majelis (dioptimalkan) yang sama:

main:
        xor     eax, eax
        ret

EDIT #2

Saya mencoba kode sederhana ini (langsung di Ideone):

#include <iostream>
using namespace std;

int main() {
    const int k1 = 10;
    constexpr int k2 = 2*k1;
    cout << k2 << '\n';
    return 0;
}

Yang menunjukkan bahwa const int k1 dievaluasi pada waktu kompilasi, seperti yang digunakan untuk menghitung constexpr int k2.

Namun, tampaknya ada perilaku berbeda untuk double. Saya telah membuat pertanyaan terpisah untuk itu di sini.

68
Mr.C64 13 Desember 2016, 19:14

1 menjawab

Variabel constexpr dijamin memiliki nilai yang tersedia pada waktu kompilasi. sedangkan variabel static const anggota atau const bisa berarti nilai waktu kompilasi atau nilai waktu proses. Mengetik constexpr mengungkapkan maksud Anda dari nilai waktu kompilasi dengan cara yang jauh lebih eksplisit daripada const.

Satu hal lagi, di C++17, constexpr variabel anggota data statis akan inline juga. Itu berarti Anda dapat menghilangkan definisi variabel static constexpr di luar garis, tetapi tidak static const.


Sebagai permintaan di bagian komentar, berikut penjelasan lebih detail tentang static const dalam lingkup fungsi.

Variabel static const pada cakupan fungsi hampir sama, tetapi alih-alih memiliki durasi penyimpanan otomatis, ia memiliki durasi penyimpanan statis. Itu berarti dalam beberapa hal setara dengan mendeklarasikan variabel sebagai global, tetapi hanya dapat diakses dalam fungsi.

Memang benar bahwa variabel static diinisialisasi pada panggilan pertama fungsi, tetapi karena itu juga const, kompilator akan mencoba untuk menyejajarkan nilai dan mengoptimalkan variabel sepenuhnya. Jadi dalam suatu fungsi, jika nilainya diketahui pada waktu kompilasi untuk variabel khusus ini, maka kompiler kemungkinan besar akan mengoptimalkannya.

Namun, jika nilainya tidak diketahui pada waktu kompilasi untuk static const pada cakupan fungsi, mungkin diam-diam membuat fungsi Anda (sedikit sangat kecil) lebih lambat, karena harus menginisialisasi nilai saat runtime saat pertama kali fungsi dipanggil. Plus, ia harus memeriksa apakah nilainya diinisialisasi setiap kali fungsi dipanggil.

Itulah keuntungan dari variabel constexpr. Jika nilainya tidak diketahui pada waktu kompilasi, itu adalah kesalahan kompilasi, bukan fungsi yang lebih lambat. Kemudian jika Anda tidak memiliki cara untuk menentukan nilai variabel Anda pada waktu kompilasi, maka kompiler akan memberi tahu Anda tentangnya dan Anda dapat melakukan sesuatu tentangnya.

46
Guillaume Racicot 4 Agustus 2017, 11:44