Apakah kode berikut ini sah?
template <int N>
class foo {
public:
constexpr foo()
{
for (int i = 0; i < N; ++i) {
v_[i] = i;
}
}
private:
int v_[N];
};
constexpr foo<5> bar;
Dentang menerimanya, tetapi GCC dan MSVC menolaknya.
Kesalahan GCC adalah:
main.cpp:15:18: error: 'constexpr foo<N>::foo() [with int N = 5]' called in a constant expression
15 | constexpr foo<5> bar;
| ^~~
main.cpp:4:15: note: 'constexpr foo<N>::foo() [with int N = 5]' is not usable as a 'constexpr' function because:
4 | constexpr foo()
| ^~~
main.cpp:4:15: error: member 'foo<5>::v_' must be initialized by mem-initializer in 'constexpr' constructor
main.cpp:12:9: note: declared here
12 | int v_[N];
| ^~
Jika kode semacam ini OK, saya bisa memotong beberapa penggunaan index_sequence
s.
_v
harus diinisialisasi dalam daftar inisialisasi, hingga C ++ 17. Mungkin diubah sesuatu di C ++ 20.int
anggotanya tidak akan pernah memiliki perilaku yang tidak terdefinisi ". Saya ingin tahu apakah GCC tidak melakukan yang sesuai, atau sebaliknya ...Jawaban:
Inisialisasi default sepele dilarang dalam
constexpr
konteks sampai C ++ 20 .Alasannya, saya menduga, adalah mudah untuk "secara tidak sengaja" membaca dari primitif yang diinisialisasi default, tindakan yang memberikan program Anda perilaku tidak terdefinisi, dan ekspresi dengan perilaku tidak terdefinisi secara langsung dilarang menjadi
constexpr
( ref ). Bahasa telah diperluas sehingga sehingga sekarang kompiler harus memeriksa apakah pembacaan tersebut terjadi dan, jika tidak, inisialisasi default harus diterima. Ini sedikit lebih banyak pekerjaan untuk kompiler, tetapi (seperti yang Anda lihat!) Memiliki manfaat besar bagi programmer.Sejak C ++ 20, sah untuk membiarkan
v_
"tidak diinisialisasi" seperti yang Anda miliki. Kemudian Anda pergi untuk menetapkan semua nilai elemennya, yang bagus.sumber
constexpr
, dan membaca sekilas proposal yang ditautkan;)