std :: is_constructible retourne une valeur incohérente pour le constructeur privé

13

Quelles sont les règles de std::is_constructiblegestion des constructeurs privés? Étant donné le code suivant:

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

Cette affiche0 ( ideone ), c'est à dire, Tn'est pas constructible par défaut.

Décommentant la ligne commentée, elle s'affiche11 ( ideone ), si Tsoudainement devenue par défaut constructible.

Je pourrais trouver un raisonnement pour soutenir les deux résultats, mais je ne comprends pas comment l'inclusion de la ligne commentée modifie le résultat de la seconde. Est-ce que cela appelle en quelque sorte UB? S'agit-il d'un bug du compilateur? Ou est-ce std::is_constructiblevraiment incohérent?

zennehoy
la source
1
Ressemble à un bug de GCC, frappe 9 impressions00
Yksisarvinen
1
Une autre pensée étrange que je remarque lors de la compilation sur ma machine avec c ++ 17 g ++ 9.2.1 / g ++ - 10.0 et en remplaçant std :: is_constructible <...> :: value par is_constructible_v <...>, est que le le résultat passe à 00
mutableVider
1
@mutableVoid Effectivement - et il semble que la ::valueversion soit capable de changer la sortie de ceux qui la précèdent aussi: godbolt.org/z/zCy5xU Décommentez la ligne commentée et tout devient 1: s dans gcc.
Ted Lyngmo
1
Une autre façon de le corriger: godbolt.org/z/EKaP3r donc, fondamentalement, il s'agit d'un bogue d'ordre d'évaluation.
Marek R
2
@mutableVoid Vous n'avez même pas besoin d'instancier le modèle de fonction pour qu'il devienne vrai. Dans cet exemple, il revient falsemais si le modèle de fonction n'est pas commenté, il retourne soudainement true: godbolt.org/z/zqxdk2
Ted Lyngmo

Réponses:

3

std::is_constructibledoit retourner falsedans ce scénario car le constructeur n'est pas accessible.

Comme indiqué sous la question, le comportement décrit dans la question est provoqué par un bogue dans GCC / libstdc ++. Le bogue est signalé ici et, selon Bugzilla, lié à s'il n'est pas provoqué par un bogue de contrôle d'accès pour les classes dans les fonctions de modèle qui n'a pas été résolu depuis un certain temps. La relation entre les deux bogues est tirée du commentaire Bugzilla de Jonathan Wakely qui semble avoir détecté la connexion entre les deux bogues en premier.

Cela est également impliqué par le fait que le comportement de ce scénario dans GCC devient correct lors de la suppression du constructeur au lieu de le rendre privé:

class Class {
    Class() = delete;
};

qui imprime 0et 00respectivement. Il s'agit de la sortie correcte (qui clangsignale correctement dans le scénario avec un constructeur privé également).

Cela pourrait expliquer le changement de comportement observé lors des commentaires dans la ligne, car à l'intérieur de la fonction dans la structure du modèle , la vérification d'accès ne fonctionne pas et signale que le constructeur est accessible lorsqu'il ne l'est pas. Lorsque le trait est vérifié à nouveau dans la ligne suivante ou éventuellement à un emplacement complètement différent (comme c'est le cas ici ), il a déjà été instancié et donne donc la mauvaise réponse.

mutableVoid
la source