Допустимо ли приводить не-классное не-массивное prvalue к cv-квалифицированному типу?
Я читал о категориях значений и натолкнулся на следующее (для краткости многое опущено):
Следующие выражения являются выражениями prvalue:
- литерал (кроме строкового литерала), такой как 42, true или nullptr;
Свойства:
- Некваливный prvalue, не являющийся массивом, не может быть квалифицирован cv.
Но... следующая программа компилируется и прекрасно работает на ideone.com и с g++ 5.4.0:
#include <iostream>
int main() {
std::cout << ((const int) 42) << std::endl;
}
Я понимаю, что компиляторы предоставляют расширения и могут выполнять любые действия, если задано неопределенное поведение. Я просто пытаюсь понять, что стандартные мандаты.
В N4296 я нашел следующее к соответствующему отрывку:
[выражение]
[... содержимое пропущено... ]
- Если значение prvalue изначально имеет тип "cv T", где T - неквалифицированный cv некласс, не массив, тип выражения корректируется до T перед любым дальнейшим анализом.
Термин "изначально" это то, что бросает меня. Не ясно, разрешено ли это как результат другого выражения, такого как пользователь для явного приведения не-класса prvalue, не являющегося массивом, к cv-квалифицированному типу (который дает другое значение prvalue), или это применяется только к "root" "выражение (42
в этом случае).
У меня вопрос: разрешает ли стандарт такие выражения (который просто удаляет cv-квалификаторы), или это запрещено (и, если необходимо, где это требуется)?
2 ответа
Спасибо SanderDeDycker за указание на соответствующую часть стандарта для поиска.
На мой вопрос ответили в следующем разделе N4296 (выделено мной):
[expr.cast]
- Результат выражения (T) cast-expression имеет тип T . Результатом является lvalue, если T является ссылочным типом lvalue или ссылкой rvalue на тип функции, и xvalue, если T является ссылкой rvalue на тип объекта; в противном случае результат является prvalue. [Примечание: если T является неклассовым типом, который квалифицирован cv, то квалификаторы cv отбрасываются при определении типа результирующего значения prvalue; см. пункт 5. - примечание к концу]
Таким образом, мы можем сделать вывод, что такие выражения, как (const int) 42
совершенно легальны C++.
Вы должны знать, что cppreference не является нормативным. "Cannot" может быть прочитано двумя способами:
Это запрещено, аля "не будет"
Это просто не может произойти, аля инварианты
Цитата, которую вы перечислили в тексте:
Если значение prvalue изначально имеет тип "cv T", где T - неквалифицированный cv некласс, не массив, тип выражения корректируется до T перед любым дальнейшим анализом.
предлагает мне, что квалифицированное CV-значение отбрасывает квалификации так же, как массивы могут распадаться на указатели (чтобы уточнить, это правило не происходит в тот момент, когда приведение будет неправильно сформировано). Дефект #1261 делает язык довольно явным о том, что и где происходит.