Cv-квалификация prvalues в С++ 14
Похоже, что С++ 11 и С++ 14 рассматривают cv-квалификацию prvalues по-разному.
С++ 11 придерживается "классического" подхода, который существует со времен С++ 98: согласно 3.10/4 "неклассовые prvalues всегда имеют cv-неквалифицированные типы".
С++ 14 содержит аналогичную формулировку в 3.10/4, но она представлена в виде примечания: "[Замечание: классы и массивы prvalues могут иметь типы cv-qual, другие prvalues всегда имеют cv-неквалифицированные типы. 5. -end note]"
И в разделе 5 говорится:
6 Если первоначально значение prvalue имеет тип "cv T", где T является неквалифицированным неклассифицированным, не-массивным типом, тип выражения доводится до T до любой дальнейший анализ. 1
Эта запись 5/6 является новой в С++ 14. Теперь он рассматривает cv-квалификацию prvalues, используя тот же подход, который всегда использовался с результатами ссылочного типа (см. 5/5).
Что может быть причиной этого изменения? С++ 11 и до того, как запретить неклассовые знаки права иметь любую cv-квалификацию. С++ 14 говорит, что неклассические, non-array prvalues могут иметь cv-квалификацию, но эти cv-квалификации отбрасываются перед любым дальнейшим анализом.
Мое предположение было бы в том, что есть некоторые новые (для С++ 14) языковые особенности, которые могут как-то "видеть" cv-квалификацию prvalues при правильных обстоятельствах (до того, как будет выполнена вышеупомянутая корректировка). Они существуют? И если да, то каковы эти функции? 2
Вопрос возник из следующего контекста: представьте себе компилятор, который внутренне реализует скрытый параметр this
класса X
как переменную типа X *const
. Поскольку компилятор должен выставлять this
как prvalue, то const
не должен приводить к каким-либо проблемам в С++ 11 (или раньше), где скалярные prvalues никогда не имеют квалификацию cv. Но как насчет С++ 14? Если тот же самый компилятор предоставляет this
как значение типа X *const
, может ли это привести к проблемам?
1 По-видимому, существует противоречие между 5/6 и примечанием в 3.10/4 в С++ 14, но заметки в любом случае не являются нормативными. И я использую черновик текста.
2 Мое первоначальное предположение было decltype
. И я даже подумал, что нашел ответ, когда попытался
std::cout << std::is_same<decltype((const int) 0), const int>::value << std::endl;
в GCC, который выводит 1
. Однако, видя, что Clang и VС++ вывод 0
(и что спецификация decltype
, похоже, не поддерживает это поведение), я склонен полагать, что это всего лишь ошибка в GCC (начиная с 6.1)
Ответы
Ответ 1
В соответствии с commit на github это было сделано для решения CWG1261: Явная обработка CV-квалификации с неклассовыми значениями
Основываясь на комментариях к вопросу, кажется, что есть место для неожиданных изменений в категории типов this
(формально prvalue) и что gcc ранее, и вместо этого MSVC вместо этого использовал const lvalue.
Формулировка подтягивает отверстие так, что, например, даже если this
по какой-то манере компилятора - это значение класса X* const
, перед любым дальнейшим анализом оно настраивается на X*
.
Аналогично, ваш данный пример выглядит как ошибка gcc. Возможно, decltype
не рассматривает тип значения перед применением c-style cast.
В настоящее время примечание в [basic.lval]/4 заключается в том, что теперь это следствие нового текста в [expr]/6, а не для указания правила в [basic.lval]/4.
Полный кредит TC за то, что он в основном ответил на это в комментариях к вопросу, включая ссылку на gcc-fix и другие другие примеры ранее -специфическое поведение для cv-квалифицированных неклассифицированных значений без массива.