Masalah bahasa yang aneh adalah CWG 1581 :
Ayat 15 [khusus] sangat jelas bahwa fungsi anggota khusus hanya didefinisikan secara implisit ketika mereka digunakan odr. Ini menciptakan masalah untuk ekspresi konstan dalam konteks yang tidak dievaluasi:
struct duration {
constexpr duration() {}
constexpr operator int() const { return 0; }
};
// duration d = duration(); // #1
int n = sizeof(short{duration(duration())});
Masalahnya di sini adalah bahwa kita tidak diizinkan untuk mendefinisikan secara implisit constexpr duration::duration(duration&&)
dalam program ini, jadi ekspresi dalam daftar penginisialisasi bukan merupakan ekspresi konstan (karena memanggil fungsi constexpr yang belum didefinisikan), sehingga penginisialisasi bracing berisi konversi penyempitan , jadi programnya salah bentuk.
Jika kita batalkan komentar pada baris # 1, konstruktor pemindahan secara implisit didefinisikan dan program tersebut valid. Aksi seram di kejauhan ini sangat disayangkan. Implementasi berbeda pada titik ini.
Anda dapat membaca deskripsi masalah lainnya.
Resolusi untuk masalah ini diadopsi di P0859 di Albuquerque pada 2017 (setelah C ++ 17 dikirim). Masalah itu adalah pemblokir untuk keduanya dapat memiliki constexpr std::swap
(diselesaikan dalam P0879 ) dan constexpr std::invoke
(diselesaikan dalam P1065 , yang juga memiliki contoh CWG1581), baik untuk C ++ 20.
Contoh paling sederhana untuk dipahami di sini, menurut pendapat saya, adalah kode dari laporan bug LLVM yang ditunjukkan dalam P1065:
template<typename T>
int f(T x)
{
return x.get();
}
template<typename T>
constexpr int g(T x)
{
return x.get();
}
int main() {
// O.K. The body of `f' is not required.
decltype(f(0)) a;
// Seems to instantiate the body of `g'
// and results in an error.
decltype(g(0)) b;
return 0;
}
CWG1581 adalah tentang kapan fungsi anggota constexpr didefinisikan, dan resolusi memastikan bahwa mereka hanya ditentukan saat digunakan. Setelah P0859, di atas terbentuk dengan baik (tipe b
is int
).
Karena std::swap
dan std::invoke
keduanya harus bergantung pada memeriksa fungsi anggota (memindahkan konstruksi / penugasan di yang sebelumnya dan operator panggilan / panggilan pengganti di yang terakhir), keduanya bergantung pada resolusi masalah ini.