Pourquoi const char * const & = “hello” comstack-t-il?

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

const char* const & a = "hello"; //can comstack 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’aura pas lieu.

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

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

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

C’est essentiellement en adhérant à 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é, affecté à l’adresse du littéral, puis lié à la référence. Dans le second cas, puisque la référence lvalue n’est pas const, cela ne peut pas arriver. Un autre exemple de plus de la même

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

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

Quelques phrases supplémentaires pour l’ennui, après avoir lu la superbe réponse de StoryTeller, car je devais passer par un processus de reflection différent à ce sujet.

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

 const char* const & a = "hello"; 

et pas ici:

 const char*& a = "hello"; 

Ce 2 e const indique que l’object référencé ici, un pointeur dans ce cas, est lui-même const , car il ne peut pas être modifié en utilisant cette référence.

Par conséquent, comme le type d’un littéral de chaîne est const char[6] (et non pas const char * par exemple), notre référence lvalue au type const char* dans la deuxième ligne ne peut pas y être lvalue – mais la référence dans la première ligne , étant une référence au type const char* const pourrait. Pourquoi? En raison de l’ initialisation des règles de référence :

[Une référence au type “cv1 T1” est initialisée par une expression de type “cv2 T2” comme suit: …]

cv1 doit être la même qualification cv que la qualification cv supérieure à cv2

Comme dans, notre T dans ce texte cité est const char* , et seulement dans la première ligne, il est qualifié de cv tout autant que notre object . c.-à-d. que le caractère const char[6] a la sémantique d’un pointeur const , par opposition à un simple pointeur sur const .

L’erreur de 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 concernant la référence de non-const lvalue est exactement cela – la lvalue dans notre cas est un pointeur sur const , mais lui-même n’est pas const! Contrairement à la première ligne.

Pour cette raison exacte, cela peut comstackr sans erreur:

 char* const & a = "hello"; 

Mis à part l’avertissement ISO C ++ 11 , un compilateur laisse passer celui-ci (ce qui 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 ), la référence étant maintenant const en ce qui concerne son object, le pointeur.

Une autre chose intéressante est qu’une référence à une rvalue référence const char* && a (no “2nd const “) pourrait se lier au pointeur temporaire qui s’est matérialisé à partir du littéral de chaîne , tel que fourni par StoryTeller. Pourquoi donc? En raison des règles de conversion de tableau en pointeur :

Une valeur ou valeur de type “tableau de NT” ou “tableau de limite inconnue de T” peut être convertie en une valeur de type “pointeur sur T” .

Aucune mention de const ou autre phrasé de qualification CV dans cette section, mais cela ne vaut que pour autant que nous initialisons une réf.