Apa yang menentukan apakah fungsi constexpr adalah ekspresi konstan?
(kompiler yang digunakan adalah gcc dengan c ++ 17 sejauh yang saya tahu (sulit ditemukan di studio visual))
#include <iostream>
using namespace std;
void increment( int& v )
{
++v;
}
int constexpr f()
{
int v = 0;
increment( v );
return v;
}
int main( )
{
cout << f( ) << '\n';
}
Kode di atas memberikan kesalahan pada kompilasi:
fungsi constexpr 'f' tidak dapat menghasilkan ekspresi konstan.
Seperti yang saya pahami, ini karena fungsinya increment
bukan constexpr. Yang membingungkan saya adalah bahwa kode berikut dapat dikompilasi dengan baik:
#include <iostream>
using namespace std;
void increment( int& v )
{
++v;
}
int constexpr f()
{
int v = 0;
for( int i = 0; i < 1; ++i )
{
increment( v );
}
return v;
}
int main( )
{
cout << f( ) << '\n';
}
Kode ini secara fungsional sama dan dikompilasi, meskipun increment masih bukan sebuah constexpr. Saya tidak mengerti bagaimana mungkin bahwa for-loop melalui range [0, 1) menyebabkan compiler menyadari bahwa fungsi f
sebenarnya adalah sebuah constexpr.
Jika ada yang bisa memberikan beberapa wawasan tentang constexpr di c ++ dan ketidakkonsistenan ini, saya akan sangat menghargainya.
Jawaban
Kedua program " cacat tidak diperlukan diagnostik", sesuai [dcl.constexpr] / 6 :
Untuk fungsi constexpr atau konstruktor constexpr yang tidak default maupun template, jika tidak ada nilai argumen sehingga pemanggilan fungsi atau konstruktor dapat menjadi subekspresi yang dievaluasi dari ekspresi konstanta inti, atau, untuk konstruktor, subekspresi yang dievaluasi dari inisialisasi ekspresi penuh dari beberapa objek yang diinisialisasi secara konstan ( [basic.start.static] ), program tidak berbentuk, tidak diperlukan diagnostik.
Agak aneh bahwa gcc gagal memperhatikan masalah dengan program kedua, tetapi masih sesuai.
Perhatikan bahwa diagnostik akan diperlukan jika f
digunakan dalam konteks yang benar-benar membutuhkan ekspresi konstan, misalnya constexpr int n = f();
.
Beberapa hal tidak pernah diizinkan dalam fungsi constexpr. Ini memang membutuhkan diagnostik (biasanya pesan kesalahan), bahkan jika fungsi tersebut tidak pernah digunakan dalam ekspresi konstan - lihat jawaban cigien . Namun program yang dimaksud tidak melanggar salah satu aturan yang lebih ketat ini.
Karena Anda tidak memanggil f
ekspresi konstan, pertanyaan Anda adalah menanyakan apakah compiler diperlukan untuk mendiagnosis yang f
tidak bisa dipanggil dalam ekspresi konstan, hanya berdasarkan definisinya .
Persyaratan tentang definisi suatu constexpr
fungsi disebutkan di sini :
Definisi dari fungsi constexpr harus memenuhi persyaratan berikut:
(3.1) tipe kembaliannya (jika ada) harus tipe literal;
(3.2) masing-masing tipe parameternya harus tipe literal;
(3.3) tidak boleh coroutine;
(3.4) jika fungsinya adalah konstruktor atau destruktor, kelasnya tidak boleh memiliki kelas basis virtual;
(3.5) badan fungsinya tidak boleh dilampirkan
(3.5.1) pernyataan goto,
(3.5.2) label pengenal,
(3.5.3) definisi variabel tipe non-literal atau durasi penyimpanan statis atau utas.
Seperti yang dapat dilihat, definisi f
tidak melanggar salah satu persyaratan dalam daftar. Jadi kompilator menyesuaikan jika memilih untuk tidak mendiagnosis ini.
Seperti yang ditunjukkan dalam jawaban aschepler , constexpr
fungsi seperti f
itu tidak dapat dipanggil dalam ekspresi konstan, tetapi tidak dapat didiagnosis seperti itu, dianggap tidak berbentuk-tidak-diperlukan-diagnostik.
Anda tidak benar-benar "menelepon" f
pada waktu kompilasi.
jika fungsi utama Anda termasuk: static_assert(f() == 1, "f() returned 1");
Saya curiga Anda akan mendapatkan kesalahan "f () bukan ekspresi konstan".
Berikut pertanyaan terkait
Standar tersebut mensyaratkan bahwa suatu constexpr
fungsi sebenarnya dapat dievaluasi pada waktu kompilasi untuk beberapa set parameter tetapi tidak semua. Tidak memerlukan kompiler untuk mendiagnosis constexpr
fungsi yang melakukan hal-hal tertentu yang mungkin bukan waktu kompilasi dalam beberapa keadaan, atau bahkan apakah fungsi tersebut memiliki sekumpulan parameter seperti itu. Ini menghindari mereka harus menyelesaikan masalah yang tersendat-sendat.