std :: is_constructible restituisce un valore incoerente per il costruttore privato


13

Quali sono le regole con cui std::is_constructiblegestisce i costruttori privati? Dato il seguente codice:

#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();
}

Questa stampa 0( ideone ), cioè Tnon è di default costruibile.

Non commentando la riga commentata, stampa 11( ideone ), Tdivenendo così improvvisamente costruibile.

Potrei trovare il ragionamento per supportare entrambi i risultati, ma non capisco come l'inclusione della riga commentata cambi il risultato del secondo. Questo in qualche modo sta invocando UB? È un bug del compilatore? O è std::is_constructibledavvero così incoerente?


1
Sembra un bug GCC, clang 9 stampe00
Yksisarvinen

1
Un'altra cosa strana che noto quando compilo sulla mia macchina con c ++ 17 g ++ 9.2.1 / g ++ - 10.0 e sostituendo std :: is_constructible <...> :: value con is_constructible_v <...>, è che il il risultato cambia in 00
mutableVoid

1
@mutableVoid In effetti - e sembra che la ::valueversione sia in grado di cambiare l'output di quelli che la precedono: godbolt.org/z/zCy5xU Uncomment la riga commentata e tutto diventa 1: s in gcc.
Ted Lyngmo

1
Un altro modo per risolverlo: godbolt.org/z/EKaP3r, quindi in pratica si tratta di un bug dell'ordine di valutazione.
Marek R

2
@mutableVoid Non è nemmeno necessario creare un'istanza del modello di funzione affinché diventi realtà. In questo esempio, restituisce falsema se il modello di funzione non è commentato, improvvisamente restituisce true: godbolt.org/z/zqxdk2
Ted Lyngmo

Risposte:


3

std::is_constructibledovrebbe tornare falsein questo scenario perché il costruttore non è accessibile.

Come sottolineato sotto la domanda, il comportamento descritto nella domanda è causato da un bug in GCC / libstdc ++. Il bug è riportato qui e, secondo Bugzilla, è correlato se non causato da un bug di controllo dell'accesso per le classi nelle funzioni del modello che è rimasto irrisolto per un bel po '. La relazione tra i due bug è tratta dal commento Bugzilla di Jonathan Wakely che sembra aver rilevato prima la connessione tra i due bug.

Ciò è anche implicito dal fatto che il comportamento di questo scenario in GCC diventa corretto quando si elimina il costruttore invece di renderlo privato:

class Class {
    Class() = delete;
};

che stampa 0e 00rispettivamente. Questo è l'output corretto (che clangriporta correttamente nello scenario anche con un costruttore privato).

Questo potrebbe spiegare il cambiamento di comportamento osservato quando si commenta nella riga, perché all'interno della funzione nella struttura basata su modelli , il controllo degli accessi non funziona e segnala che il costruttore è accessibile quando non lo è. Quando il tratto viene ricontrollato nella riga successiva o possibilmente in una posizione completamente diversa (come nel caso qui ), è già stato istanziato e quindi fornisce la risposta sbagliata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.