const_cast(char * const) не lvalue? - PullRequest
       82

const_cast(char * const) не lvalue?

0 голосов
/ 31 октября 2019

При компиляции кода ниже я получаю сообщение об ошибке в строке 3 о том, что const_cast не является lvalue. Это только проблема, потому что я использовал gcc 7.x (даже если он полностью совместим с C ++ 17)? Или это действительно неверный код в соответствии со стандартом?

Приведенный ниже код является минимальным примером, вызывающим ошибку. Пробовал gcc 7.1, 7.4, а также https://www.onlinegdb.com/online_c++_compiler и получал такую ​​же ошибку.

char* const a = "xyz";
char* b;
const_cast<char*>(a) = b;  // not lvalue error

Точная ошибка, которую дает gcc: «error: lvalue требуется в качестве левого операнда присваивания».

ПРИМЕЧАНИЕ (забыл добавить): пример не имеет ничего общего с реальным кодомЯ бы когда-нибудь написал. Я привел пример, который (я полагаю) был создан, чтобы проверить, насколько хорошо люди понимают стандарт. Поэтому меня интересует только то, что я задал в вопросе, т. Е. Является ли это действительным кодом или нет (и почему). Thx!

Ответы [ 4 ]

3 голосов
/ 31 октября 2019

Во-первых, char* const a = "xyz"; недопустимо. строковый литерал имеет тип const char[N] и присвоение ему char * const удаляет константность символов, недопустимых в неявном приведении.

Теперь давайте притворимся, что все в порядке и давайте посмотрим на

const_cast<char*>(a) = b

У этого есть две проблемы. Во-первых, const_cast<char*>(a) приводит к rvalue. Для типов, не относящихся к классам, вы не можете назначать значения r. Вам потребуется const_cast<char*&>(a), чтобы иметь lvalue для назначения, и это поднимает следующую проблему. Вы не можете присвоить объекту const. Удаление const с использованием const_cast не решает проблему. Это все еще не разрешено для [dcl.type.cv] / 4

Любая попытка изменить ([expr.ass], [expr.post.incr], [expr.pre.incr]) константный объект ([basic.type.qualifier]) в течение его времени жизни ([basic.life]) приводит к неопределенному поведению.

Даже при правильном приведении базовый объект по-прежнему const, поэтому вы нарушаете вышеприведенное предложение и ведете неопределенное поведение.

3 голосов
/ 31 октября 2019

Так что меня интересует только то, что я задал в вопросе, т. Е. Является ли это действительным кодом или нет

Это не так. Результат const_cast является glvalue (lvalue или xvalue) только при приведении к ссылочному типу.

[expr.const.cast] (выделение мое)

1 Результат выражения const_­cast<T>(v) имеет тип T. Если T является ссылкой lvalue на тип объекта, результатом является lvalue;если T является rvalue ссылкой на тип объекта, результатом является xvalue; в противном случае результатом является значение prvalue , и стандартные преобразования lvalue-to-rvalue, array-to-pointer и function-to-pointer выполняются для выражения v. Преобразования, которые могут быть выполнены явно с использованием const_­cast перечислены ниже. Никакое другое преобразование не должно выполняться явно с использованием const_­cast.

. Вы не приводите к ссылочному типу, поэтому результатом является значение prvalue;не то, что вы можете назначить. И не переходите к ссылочному типу;попытка изменить объект, объявленный как const, приводит к неопределенному поведению. Тогда ваша программа будет недействительной.

0 голосов
/ 31 октября 2019

lvalue - это синтаксическая конструкция, означающая своего рода выражение, которое может появиться слева от присваивания. Вы можете присвоить переменную, или компонент массива, или поле, но это синтаксическая ошибка, чтобы записать присваивание другим выражениям, таким как x + y = 7; или f(x) = 5;. Вызов функции, такой как const_cast<char*>(a), не является видом выражения, которому можно присвоить.

Синтаксически допустимо записать a = const_cast<char*>(b);, где вызов функции появляется справа от назначения.

0 голосов
/ 31 октября 2019

Тип char * const a определяет переменную-указатель a, которая не может быть изменена, но указывает на символы, которые могут быть изменены. Это не обычное использование, чтобы сделать указатель постоянным.

Ошибка говорит вам, что вы не можете обновить значение a - это не lvalue, и я не верю, что const_cast получаетвокруг этого в этом случае.

Не могли бы вы иметь в виду const char *a, который позволяет изменять сам указатель, но не вещи, на которые указывает?

...