c++ Pourquoi const char*const &=“hello” peut-il être compilé?




reference language-lawyer (2)

C'est essentiellement adhérer à cette formule

T const & a = something_convertible_to_T;

Où T est const char* . Dans le premier cas, un pointeur temporaire peut être matérialisé, attribué à l'adresse du littéral, puis être lié à la référence. Dans le second cas, puisque la référence de lvalue n'est pas const, cela ne peut pas arriver. Un autre exemple de plus de la même chose

const char* && a = "hello"; // rvalue ref makes a no into a yes.

Maintenant, le pointeur temporaire est lié à une référence rvalue.

Je lis un extrait de code d'un livre et trouve ceci:

const char* const & a = "hello"; //can compile 
const char*& a = "hello"; //cannot

Tout ce que je sais, c'est que lors de l'initialisation d'une référence, la conversion de tableau en pointeur n'aurait pas lieu.

const char* const & , une référence à un const pointer , le pointeur pointe vers const char .

const char*& , une référence à un pointer , le pointeur pointe à const char .

Alors pourquoi ajouter un const supplémentaire, indiquant que le pointeur est un const , lui permet-il de compiler?


Quelques phrases supplémentaires pour ceux qui s'ennuient, après avoir lu la superbe réponse de @StoryTeller, car j'ai dû mener une réflexion différente à ce sujet.

Donc, syntaxiquement, dans les deux lignes, nous définissons une référence a et, dans les deux cas, nous allons matérialiser un pointeur temporaire prenant l'adresse du littéral de chaîne . La seule différence entre les deux est la 2ème const apparaissant seulement ici:

const char* const & a = "hello";

et pas ici:

const char*& a = "hello";

Cette 2ème const indique que l'objet référencé ici, un pointeur dans ce cas, est lui-même constant , car il ne peut pas être modifié avec cette référence.

Par conséquent, puisque le type de ce littéral de chaîne est const char[6] (et non const char * par exemple), notre référence lvalue au type const char* de la deuxième ligne ne peut pas être liée à celui-ci - mais la référence de la première ligne , étant une référence au type const char* const pourrait. Pourquoi? En raison des règles d' initialisation des références :

(5) Une référence au type "cv1 T1" est initialisée par une expression de type "cv2 T2" comme suit:

  • (5.1) Si la référence est une référence lvalue et l'expression de l'initialiseur

    • (5.1.1) est une valeur lvalue (mais n'est pas un champ de bits), et «cv1 T1» est compatible avec la référence avec «cv2 T2», [...]
    • (5.1.2) a un type de classe (c'est-à-dire que T2 est un type de classe) [...]

Les deux expressions sont lvalue s, mais notre «cv1 T1» n’est pas reference-compatible avec notre référence «cv2 T2» et «T2» n’est pas un type de classe.

  • (5.2) Sinon, si la référence est une référence à la valeur lvalue vers un type qui n'est pas qualifié constant ou qualifié qualifié, le programme est mal formé.

La référence n'est en effet pas qualifiée de const: notre "T1" est const char* , qui est un pointeur sur const , par opposition à un pointeur const . Le type réel ici est un type de pointeur, c'est donc ce qui compte.

L'erreur Clang pour la deuxième ligne, lue dans cet esprit, nous dit exactement ceci:

error: non-const lvalue reference to type 'const char *' cannot bind to a value of unrelated type 'const char [6]'
    const char*& a = "hello";
                 ^    ~~~~~~~

La partie sur le fait d'être non-const référence de lvalue est exactement ¶5.2 - la lvalue dans notre cas est un pointeur sur const , mais elle-même n'est pas const! Contrairement à la première ligne. La partie relative à la liaison à un type non lié est exactement ¶5.1 - notre const char* n'est pas compatible avec le RHS étant const char[6] , ou const char* const après la conversion de tableau en pointeur .

Pour cette raison exacte, ou son absence, cela peut compiler sans erreur:

char* const & a = "hello";

Mis à part l’avertissement ISO C ++ 11 , un compilateur laisse passer celui-ci (ce n’est pas le cas, car le littéral de chaîne est un 'const char 6 ' et nous ne devrions pas supprimer ce premier const ), car la référence est maintenant const avec en ce qui concerne son objet, le pointeur.

Une autre chose intéressante est qu’une référence rvalue const char* && a (no "2nd const ") pourrait se lier au pointeur temporaire qui s’est matérialisé à partir du littéral chaîne , comme l’a fourni lui-même @StoryTeller. Pourquoi donc? En raison des règles de 6 de 6

Une valeur ou une valeur de type "tableau de NT" ou "tableau de bornes inconnues de T" peut être convertie en une valeur de type "pointeur sur T" .

Aucune mention de const ou d'une autre formulation cv-qualification dans ce chapitre, mais ceci n’est valable que tant que nous initialisons une référence rvalue.





language-lawyer