std :: is_constructible mengembalikan nilai yang tidak konsisten untuk konstruktor pribadi

13

Apa aturan yang std::is_constructiblemenangani konstruktor pribadi? Diberikan kode berikut:

#include <iostream>

class Class {
private:
    Class() { }
};

template <typename T>
class Test {
public:
    static void test() {
        std::cout
            //<< std::is_constructible<Class>::value
            << std::is_constructible<T>::value
            << std::endl;
    }
};

int main() {
    Test<Class>::test();
}

Cetakan ini 0( ideone ), yaitu, Ttidak dapat dibangun secara default.

Membatalkan komentar pada baris yang dikomentari, ia mencetak 11( ideone ), jadi Ttiba-tiba menjadi default dibangun.

Saya dapat menemukan alasan untuk mendukung kedua hasil, tetapi saya tidak mengerti bagaimana memasukkan baris komentar mengubah hasil yang kedua. Apakah ini entah bagaimana melibatkan UB? Apakah ini bug kompiler? Atau std::is_constructiblebenar-benar tidak konsisten?

Zennehoy
sumber
1
Tampak seperti bug GCC, cetakan 9 dentang00
Yksisarvinen
1
Rasa aneh lain yang saya perhatikan ketika mengkompilasi di komputer saya dengan c ++ 17 g ++ 9.2.1 / g ++ - 10.0 dan mengganti std :: is_constructible <...> :: value dengan is_constructible_v <...>, adalah bahwa hasil berubah menjadi 00
mutableVoid
1
@mutableVoid Memang - dan tampaknya ::valueversi ini mampu mengubah output dari yang datang sebelumnya juga: godbolt.org/z/zCy5xU Batalkan komentar pada baris yang dikomentari dan semuanya menjadi 1: dalam gcc.
Ted Lyngmo
1
Cara lain untuk memperbaikinya: godbolt.org/z/EKaP3r jadi pada dasarnya ini adalah semacam bug urutan evaluasi.
Marek R
2
@mutableVoid Anda bahkan tidak perlu membuat instance templat fungsi agar menjadi benar. Dalam contoh ini, ia kembali falsetetapi jika templat fungsi tidak dicommentasikan, tiba-tiba kembali true: godbolt.org/z/zqxdk2
Ted Lyngmo

Jawaban:

3

std::is_constructibleharus kembali falsedalam skenario ini karena konstruktor tidak dapat diakses.

Seperti yang ditunjukkan di bawah pertanyaan, perilaku yang dijelaskan dalam pertanyaan disebabkan oleh bug di GCC / libstdc ++. Bug dilaporkan di sini , dan, menurut Bugzilla, terkait dengan jika tidak disebabkan oleh bug kontrol akses untuk kelas-kelas dalam fungsi templat yang tidak terselesaikan selama beberapa waktu. Hubungan antara kedua bug tersebut diambil dari komentar Bugzilla Jonathan Wakely yang tampaknya telah mendeteksi hubungan antara kedua bug terlebih dahulu.

Ini juga tersirat oleh fakta bahwa perilaku skenario ini di GCC menjadi benar ketika menghapus konstruktor alih-alih menjadikannya pribadi:

class Class {
    Class() = delete;
};

yang mencetak 0dan 00masing - masing. Ini adalah output yang clangbenar (yang dengan benar melaporkan dalam skenario dengan konstruktor pribadi juga).

Ini bisa menjelaskan perubahan perilaku yang diamati ketika berkomentar di baris, karena di dalam fungsi dalam templated struct, pemeriksaan akses tidak berfungsi dan melaporkan bahwa konstruktor dapat diakses ketika tidak. Ketika sifat diperiksa lagi di baris berikutnya atau mungkin di lokasi yang sama sekali berbeda (seperti halnya di sini ), itu sudah dipakai, dan dengan demikian menghasilkan jawaban yang salah.

dapat dibatalkan
sumber