Несколько дополнительных фраз для скучающих, после прочтения превосходного ответа @StoryTeller, поскольку мне пришлось пройти через другой мыслительный процесс по этому поводу.
Так что синтаксически, В обеих строках мы определяем ссылка a
, и в обоих случаях у нас будет материализация временного указателя , который принимает адрес строкового литерала . Единственное различие между ними состоит в том, что 2-й const
появляется только здесь:
const char* const & a = "hello";
, а не здесь:
const char*& a = "hello";
Этот 2-й const
обозначаетчто объект , на который ссылается здесь, указатель в этом случае, сам является const , поскольку в нем нельзя изменить эту ссылку.
Следовательно, поскольку тип этого строкового литерала равен const char[6]
(и не const char *
, например), наша lvalue
ссылка на тип const char*
во второй строке не может привязаться к нему -но ссылка в первой строке, являющаяся ссылкой на тип const char* const
, могла бы.Зачем?Из-за правил инициализации ссылки :
(5) Ссылка на тип «cv1 T1» инициализируется выражением типа «cv2 T2»”Следующим образом:
Оба выражения lvalue s, но наш «cv1 T1» не ссылка совместима с нашими «cv2 T2» и «T2» не является типом класса.
- (5.2) В противном случае, еслиссылка является lvalue ссылкой на тип, который не является константным или нестабильным, программа имеет неправильную форму
Ссылка действительно не const-qualified: наш «T1» равен const char*
, который является указателем на const , в отличие от const указателя .Фактический тип здесь является типом указателя, так что вот что имеет значение.
Ошибка Clang для второй строки, прочитанная с учетом этого, говорит нам именно это:
error: non-const lvalue reference to type 'const char *' cannot bind to a value of unrelated type 'const char [6]'
const char*& a = "hello";
^ ~~~~~~~
часть о том, что неконстантная ссылка lvalue в точности равна .25.2 - lvalue в нашем случае это указатель на const
, но сам по себе не является const!В отличие от первой строки.Часть о привязке к несвязанному типу точно равна .15.1 - наша const char*
не совместима с RHS, равным const char[6]
или const char* const
после преобразование массива в указатель .
По этой точной причине или ее отсутствию компиляция может происходить без ошибок:
char* const & a = "hello";
ISO C ++ 11 , кроме предупреждения, компилятор позволяет этоpass (не так, как должно, так как строковый литерал является 'const char 6 ', и мы не должны отбрасывать этот первый const
), так как ссылка теперь const
относительно егообъект, указатель.
Другая интересная вещь заключается в том, что rvalue
ссылка const char* && a
(без "2nd const
") может привязаться к временному указателю, материализованному из строковый литерал , как предоставил сам @StoryTeller.Это почему?Из-за правил преобразование массива в указатель :
Lvalue или rvalue типа "массив NT"" или" массив неизвестных границ T " может быть преобразован в prvalue типа" указатель на T ".
Нет упоминанияиз const
или другого cv-qualification , формулируемого здесь, но это остается только до тех пор, пока мы инициализируем rvalue ref.