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.