Почему const char * const & = "hello" компилируется? - PullRequest
0 голосов
/ 27 августа 2018

Я читаю фрагмент кода из книги и нахожу это:

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

Все, что я знаю, это то, что при инициализации ссылки преобразование массива в указатель не будет иметь места,

const char* const &, ссылка на const pointer, указатель указывает на const char.

const char*&, ссылка на pointer, указатель на const char.

Так почему же добавление дополнительного const, указывающего, что указатель является const, позволяет его компилировать?

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Несколько дополнительных фраз для скучающих, после прочтения превосходного ответа @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»”Следующим образом:

  • (5.1) Если ссылка является ссылкой lvalue, а выражение инициализатора

    • (5.1.1) является значением lvalue (ноне битовое поле), и «cv1 T1» совместим со ссылками с «cv2 T2», [...]
    • (5.1.2) имеет тип класса (т. е. 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.

0 голосов
/ 27 августа 2018

Это по существу придерживается этой формулы

T const & a = something_convertible_to_T;

, где Т - const char*.В первом случае временный указатель может быть материализован, назначен адрес литерала, а затем привязан к ссылке.Во втором случае, поскольку ссылка lvalue не является константой, это не может произойти.Другой пример того же

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

Теперь временный указатель привязан к rvalue-ссылке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...